Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I have non owning shared pointers?

Intro

The question arose from the need for a conditional interface. It may be so that I fell into an XY problem, but (bottom line) I ended up needing a shared pointer that would ( based on a runtime choice ) either manage or not (own or not) a resource.

Work so far

The following are some thoughts on a non owning shared pointer

  1. Using placement new, eg:

    struct MyStruct {}; 
    MyStruct ms1; 
    std::shared_ptr<MyStruct> sp(new(&ms1) MyStruct); 
    
  2. Using a dummy deleter

    std::shared_ptr<MyStruct> spn(new MyStruct, [](MyStruct*){}); 
    

Question

  • Is there a standard proposed way?
  • Is there a "don't do it" rule?
  • Is there at least a better way?

Notes

My class layout (where the non owning shared pointer will be used) looks like this:

template<typename T>
struct blah
{
    shared_ptr<T> _m;
};

Now, the _m member may or may not own a resource based on a runtime choice. The reason I'm not using weak_ptr is because _m may actually be an owning pointer.

like image 650
Nikos Athanasiou Avatar asked Oct 06 '14 12:10

Nikos Athanasiou


2 Answers

The placement new is obviously UB, since it will in your snippet attempt to delete something on the stack. The empty deleter version will work but will allocate a reference counting block.

The trick is to use the crazy (ok, aliasing) constructor of shared_ptr:

template< class Y > 
shared_ptr( const shared_ptr<Y>& r, T *ptr );

that constructs a shared_ptr owning what r owns, but pointing to what ptr points to, i.e.:

std::shared_ptr<MyStruct> sp(std::shared_ptr<MyStruct>(), p);

This is guaranteed noexcept by the standard, and will not allocate anything. The standard even has a note that says

[ Note: This constructor allows creation of an empty shared_ptr instance with a non-null stored pointer. —end note ]

like image 183
T.C. Avatar answered Sep 19 '22 23:09

T.C.


The placement new will give you undefined behaviour (and likely a crash) on destruction - it will promptly call delete on something which was not created with new.

I'd go with the no-op deleter. The design may seem odd, but if you need such behaviour (and document it enough), it will work. I used something like this in one of my projects for a while, but then I got rid of the need for it.

like image 42
Angew is no longer proud of SO Avatar answered Sep 19 '22 23:09

Angew is no longer proud of SO