Git Product home page Git Product logo

nn's Introduction

nn: Non-nullable pointers for C++

nn is a type that helps you enforce at compile time the contract that a given pointer can't be null. It wraps around raw pointers or smart pointers, and works particularly well out of the box with std::unique_ptr and std::shared_ptr.

Here's an example:

class Widget : public WidgetBase {
public:
  Widget(nn_shared_ptr<Gadget> gadget) : m_gadget(move(gadget)) {}
  // ...
private:
  nn_shared_ptr<Gadget> m_gadget;
};

// nn_make_unique and nn_make_shared always return non-null values
nn_unique_ptr<Widget> my_widget = nn_make_unique<Widget>(nn_make_shared<Gadget>());

// but what if we have a pointer already and we don't know if it's null?
shared_ptr<Gadget> this_might_be_null = ...
my_widget = nn_make_unique<Widget>(NN_CHECK_ASSERT(this_might_be_null));

// implicit nn_unique_ptr -> nn_shared_ptr works just like unique_ptr -> shared_ptr
nn_shared_ptr<Widget> shared_widget = move(my_widget);

// the `nn` implicitly casts away if needed
void save_ownership_somewhere(shared_ptr<Widget>);
save_ownership_somewhere(shared_widget);

// implicit upcasts work too
nn_shared_ptr<WidgetBase> base_ptr = shared_widget;

Compile-time checking helps find bugs sooner. At Dropbox we use nn pervasively in our cross-platform C++ codebase.

Compatibility

nn is C++11 compatible. Tested with GCC 4.8, clang 3.6+ and MSVS 2015.

nn's People

Contributors

artwyman avatar j4cbo avatar nlohmann avatar webmaster128 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nn's Issues

Code style question: null check and assignment

After using nn in our project, I now have some places where I need to check a shared_ptr for null and conditionally assign it to nn_shared_ptr, e.g.

std::shared_ptr resultNullable = methodReturningNullOnError();
if (resultNullable) {
    auto result = NN_CHECK_ASSERT(resultNullable);
    // go on with `result`
}

Is there a way to rewrite this without the extra variable resultNullable?

In Swift there is the if let construct built into the language, that does null check and assignment in one step. Can something like this be done in an elegant way on the caller side?

cannot assign nn_shared_ptr to std::map entry

Awesome little library :)

Unfortunately nn_shared_ptr doesn't work with std::map or std::unordered_map while shared_ptr does work just fine.

What's causing this?

test_nn.cpp

#include "nn.hpp"

#include <map>

using namespace dropbox::oxygen;

int main() {
    std::map<int, nn_shared_ptr<int>> ints;
    ints[0] = nn_make_shared<int>(1); // fails

    return 0;
}

Output:

$ c++ -std=c++11 test_nn.cpp 

In file included from test_nn.cpp:1:
In file included from ./nn.hpp:20:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/memory:638:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/tuple:1356:7: error: no matching constructor for initialization of 'dropbox::oxygen::nn<std::__1::shared_ptr<int> >'
      second(_VSTD::forward<_Args2>(_VSTD::get<_I2>(__second_args))...)
      ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/utility:484:11: note: in instantiation of function template specialization 'std::__1::pair<const int,
      dropbox::oxygen::nn<std::__1::shared_ptr<int> > >::pair<int &&, 0>' requested here
        : pair(__pc, __first_args, __second_args,
          ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/memory:1783:31: note: in instantiation of function template specialization 'std::__1::pair<const int,
      dropbox::oxygen::nn<std::__1::shared_ptr<int> > >::pair<int &&>' requested here
            ::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
                              ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/memory:1694:18: note: in instantiation of function template specialization
      'std::__1::allocator<std::__1::__tree_node<std::__1::__value_type<int, dropbox::oxygen::nn<std::__1::shared_ptr<int> > >, void *> >::construct<std::__1::pair<const int, dropbox::oxygen::nn<std::__1::shared_ptr<int> > >, const
      std::__1::piecewise_construct_t &, std::__1::tuple<int &&>, std::__1::tuple<> >' requested here
            {__a.construct(__p, _VSTD::forward<_Args>(__args)...);}
                 ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/memory:1540:14: note: in instantiation of function template specialization
      'std::__1::allocator_traits<std::__1::allocator<std::__1::__tree_node<std::__1::__value_type<int, dropbox::oxygen::nn<std::__1::shared_ptr<int> > >, void *> > >::__construct<std::__1::pair<const int,
      dropbox::oxygen::nn<std::__1::shared_ptr<int> > >, const std::__1::piecewise_construct_t &, std::__1::tuple<int &&>, std::__1::tuple<> >' requested here
            {__construct(__has_construct<allocator_type, _Tp*, _Args...>(),
             ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/__tree:2163:20: note: in instantiation of function template specialization
      'std::__1::allocator_traits<std::__1::allocator<std::__1::__tree_node<std::__1::__value_type<int, dropbox::oxygen::nn<std::__1::shared_ptr<int> > >, void *> > >::construct<std::__1::pair<const int,
      dropbox::oxygen::nn<std::__1::shared_ptr<int> > >, const std::__1::piecewise_construct_t &, std::__1::tuple<int &&>, std::__1::tuple<> >' requested here
    __node_traits::construct(__na, _NodeTypes::__get_ptr(__h->__value_), _VSTD::forward<_Args>(__args)...);
                   ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/__tree:2108:29: note: in instantiation of function template specialization 'std::__1::__tree<std::__1::__value_type<int,
      dropbox::oxygen::nn<std::__1::shared_ptr<int> > >, std::__1::__map_value_compare<int, std::__1::__value_type<int, dropbox::oxygen::nn<std::__1::shared_ptr<int> > >, std::__1::less<int>, true>,
      std::__1::allocator<std::__1::__value_type<int, dropbox::oxygen::nn<std::__1::shared_ptr<int> > > > >::__construct_node<const std::__1::piecewise_construct_t &, std::__1::tuple<int &&>, std::__1::tuple<> >' requested here
        __node_holder __h = __construct_node(_VSTD::forward<_Args>(__args)...);
                            ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/map:1376:20: note: in instantiation of function template specialization 'std::__1::__tree<std::__1::__value_type<int,
      dropbox::oxygen::nn<std::__1::shared_ptr<int> > >, std::__1::__map_value_compare<int, std::__1::__value_type<int, dropbox::oxygen::nn<std::__1::shared_ptr<int> > >, std::__1::less<int>, true>,
      std::__1::allocator<std::__1::__value_type<int, dropbox::oxygen::nn<std::__1::shared_ptr<int> > > > >::__emplace_unique_key_args<int, const std::__1::piecewise_construct_t &, std::__1::tuple<int &&>, std::__1::tuple<> >'
      requested here
    return __tree_.__emplace_unique_key_args(__k,
                   ^
test_nn.cpp:9:9: note: in instantiation of member function 'std::__1::map<int, dropbox::oxygen::nn<std::__1::shared_ptr<int> >, std::__1::less<int>, std::__1::allocator<std::__1::pair<const int,
      dropbox::oxygen::nn<std::__1::shared_ptr<int> > > > >::operator[]' requested here
    ints[0] = nn_make_shared<int>(1);
        ^
./nn.hpp:116:14: note: candidate constructor template not viable: requires single argument 'other', but no arguments were provided
    explicit nn(const nn<OtherType> & other) : ptr(other.operator const OtherType & ()) {}
             ^
./nn.hpp:124:14: note: candidate constructor template not viable: requires single argument 'other', but no arguments were provided
    explicit nn(nn<OtherType> && other) : ptr(std::move(other).operator OtherType && ()) {}
             ^
./nn.hpp:130:5: note: candidate constructor template not viable: requires single argument 'other', but no arguments were provided
    nn(const nn<OtherType> & other) : ptr(other.operator const OtherType & ()) {}
    ^
./nn.hpp:137:5: note: candidate constructor template not viable: requires single argument 'other', but no arguments were provided
    nn(nn<OtherType> && other) : ptr(std::move(other).operator OtherType && ()) {}
    ^
./nn.hpp:149:5: note: candidate constructor template not viable: requires 2 arguments, but 0 were provided
    nn(const nn<OtherType> & ownership_ptr, nn<element_type *> target_ptr)
    ^
./nn.hpp:100:5: note: candidate constructor not viable: requires 1 argument, but 0 were provided
    nn(std::nullptr_t) = delete; // nullptr is not allowed here
    ^
./nn.hpp:102:5: note: candidate constructor not viable: requires 1 argument, but 0 were provided
    nn(PtrType) = delete; // must use NN_CHECK_ASSERT or NN_CHECK_THROW
    ^
./nn.hpp:71:7: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 0 were provided
class nn {
      ^
./nn.hpp:71:7: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided
./nn.hpp:106:14: note: candidate constructor not viable: requires 2 arguments, but 0 were provided
    explicit nn(i_promise_i_checked_for_null_t, const PtrType & arg) : ptr(arg) { assert(ptr); }
             ^
./nn.hpp:107:14: note: candidate constructor not viable: requires 2 arguments, but 0 were provided
    explicit nn(i_promise_i_checked_for_null_t, PtrType && arg) : ptr(std::move(arg)) { assert(ptr); }
             ^
1 error generated.

nn_shared_ptr needs lifetime-sharing constructors

nn<> doesn't have the lifetime-sharing constructors for shared_ptr, which allow creating a new shared_ptr which shares its refcount with a shared_ptr (see (8) here).

Adding it would require some additional specialization (or accepting having some ctors which won't compile when used) since that constructor wouldn't be applicable to all pointer types (e.g. unique_ptr).

Meanwhile you can work around this by creating a normal shared_ptr, then converting it to nn<> using i_promise_i_checked_for_null. A helper function which does this might be a reasonable compromise.

Is nn c++11 compatible?

When reading the nn code, we found generic lambdas in NN_CHECK_ASSERT and NN_CHECK_THROW, which require c++14, right?

Now those are called "sample implementations" in the comment at the top, so those might be kind of optional.

Is it possible to make the core of nn a C++11 project?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.