Preamble
In C++11 there is std::shared_ptr
+ std::weak_ptr
combo. Despite being very useful, it has a nasty issue: you cannot easily construct shared_ptr from a raw pointer. As a result of this flaw, such smart pointers usually become "viral": people start to completely avoid raw pointers and references, and use exclusively shared_ptr and weak_ptr smart pointers all over the code. Because there is no way to pass a raw reference into a function expecting a smart pointer.
On the other hand, there is boost::intrusive_ptr
. It is equivalent to std::shared_ptr
and can easily be constructed from raw pointer, because reference counter is contained within the object. Unfortunately, there is no weak_ptr companion to it, so there is no way to have non-owning references which you could check for being invalid. In fact, some believe that weak companion for intrusive_ptr is impossible.
Now, there is std::enable_shared_from_this
, which embeds a weak_ptr directly into your class, so that you could construct shared_ptr from pointer to object. But there is small limitation (at least one shared_ptr must exist), and it still does not allow the obvious syntax: std::shared_ptr(pObject)
.
Also, there is a std::make_shared
, which allocates reference counters and the user's object in a single memory chunk. This is very close to the concept of intrusive_ptr, but the user's object can be destroyed independently of the reference counting block. Also, this concept has an inevitable drawback: the whole memory block (which can be large) is deallocated only when all weak_ptr-s are gone.
Question
The main question is: how to create a pair of shared_ptr/weak_ptr, which would have the benefits of both std::shared_ptr
/std::weak_ptr
and boost::intrusive_ptr
?
In particular:
- shared_ptr models shared ownership over the object, i.e. the object is destroyed exactly when the last shared_ptr pointing to it is destroyed.
- weak_ptr does not model ownership over the object, and it can be used to solve the circular dependency problem.
- weak_ptr can be checked for being valid: it is valid when there exists a shared_ptr pointing to the object.
- shared_ptr can be constructed from a valid weak_ptr.
- weak_ptr can be constructed from a valid raw pointer to the object. Raw pointer is valid if there exists at least one weak_ptr still pointing to that object. Constructing weak_ptr from invalid pointer results in undefined behavior.
- The whole smart pointer system should be cast-friendly, like the abovementioned existing systems.
It is OK for being intrusive, i.e. asking the user to inherit once from given base class. Holding the object's memory when the object is already destroyed is also OK. Thread safety is very good to have (unless being too inefficient), but solutions without it are also interesting. It is OK to allocate several chunks of memory per object, though having one memory chunk per object is preferred.
std::shared_ptr
+std::weak_ptr
are very usable, and I have used them successfully myself. However, this question is intended to call for a better design, which does not have this "nuisance". – stgatilov