Jiří Lechner Jiří Lechner - 3 months ago 13
C++ Question

Unexpected behavior of smart pointers

I am trying to get the managed object of an aliased shared pointer. My idea was using a weak pointer. Since weak pointers doesn't yield any objects I thought creating a weak pointer from a shared pointer would make the weak pointer forget the stored object of the aliased shared pointer and hence locking the weak pointer would yield a shared pointer with the equal stored and managed pointers. But the results I got confuse me. Does the weak pointer remember from what share pointer is constructed? And is there a way how to get the managed object of an aliased shared pointer?

template<class T> struct Deleter {
void operator()(T* p) const {};
};

Deleter<T> d {};
T t1 {};
T* p1 = &t1;
T t2 {};
T* p2 = &t2;
auto sp1 = std::shared_ptr<T>(p1,d);
auto sp2 = std::shared_ptr<T>(sp1,p2);
auto wp = std::weak_ptr<T>(sp2);
std::cout << sp1.get() << " " << sp2.get() << " " << wp.lock().get() << std::endl;


produce
0x7fff5798c958 0x7fff5798c948 0x7fff5798c948

Answer

Does the weak pointer remember from what share pointer is constructed?

It remembers the raw pointer which was stored by the shared_ptr from which it was constructed. I think it would be very confusing if things worked the way you are expecting. For example, if a function recieved a shared_ptr<T> as an argument, it has no idea whether it is aliasing or not. And if that function then wanted to take a weak_ptr from that shared_ptr, it would, I think, be very surprising behavior to find that actualizing that weak_ptr to a shared_ptr gave a completely different object than the original shared_ptr from which it was obtained.

Also note that the aliasing shared_ptr can store a different type than the shared_ptr which it is aliasing. The types don't even have to be convertible to/from each other. And a weak_ptr which is constructed from an aliasing shared_ptr gets its stored type from the shared_ptr it was constructed from (or an implicitly convertible type).

The most common use case for an aliasing shared_ptr, I would suspect (even though I've never had need for one), would be to pass around a member of a shared object, and to be sure it stays alive even if the rest of the owned object is no longer needed. So the scenario which you've constructed, where the type of the aliasing shared_ptr is the same as the original, seems like it would be uncommon.

And is there a way how to get the managed object of an aliased shared pointer?

As far as I'm aware, no. Perhaps there should be. If you think this feature would be useful, propose it. https://groups.google.com/a/isocpp.org/forum/?fromgroups#!forum/std-proposals