In hindsight, given make_shared
, would shared_ptr
have a constructor that takes a raw pointer had it been introduced with C++11?
Are there strong arguments or use cases in favor of this constructor?
It would have avoided the well documented pitfall of exception-safety and the memory allocation/performance advantage of using make_shared
.
I believe another advantage of requiring shared_ptr
construction via make_shared
would be that it could be a single pointer under the hood, lowering its memory use and making things like atomic_compare_exchange a lot simpler (and possibly more efficient). (see presentation from C++Now)
I understand that a shared_ptr that basically is an intrusive_ptr (with the object and the control block coalesced) would lack features the current std::shared_ptr has. Like:
the ability to free the object separately from the control block (which is nice if you have long lived weak_ptrs)
compatibility with libraries that hand you raw pointers and the responsibility to free them
the ability to hold arbitrary resources with custom deleters (or no deleter, for non-owning pointers)
the ability to point to a sub-object (e.g., a member) while keeping the parent object alive.
What I'm suggesting is that these features may not be used commonly enough (or in the case of using it as a RAII-wrapper) may not be the best fit, to warrant the extra cost:
In a C++98 world (where shared_ptr was introduced) make_shared is less practical and less user friendly (the lack of perfect forwarding requires reference wrappers and the lack of variadic templates makes the implementation clunky).
Therefore, when you create a std::shared_ptr from another one, it will increment the count properly (the two std::shared_ptr s point to the same struct). If you create two std::shared_ptr from the same raw pointer, although they actually point to the same resource, they have no way of knowing it!
The raw pointer overloads assume ownership of the pointed-to object. Therefore, constructing a shared_ptr using the raw pointer overload for an object that is already managed by a shared_ptr, such as by shared_ptr(ptr.get()) is likely to lead to undefined behavior, even if the object is of a type derived from std::enable_shared_from_this .
No, the shared_ptr takes ownership of the pointer and deletes it when there are no references anymore. See: Sorry I provided some wrong information . What if parent is a class member as follows:
The reason why it can keep track is because std::shared_ptr has a pointer to a struct that stores the reference count besides the pointer to the actual object. Therefore, when you create a std::shared_ptr from another one, it will increment the count properly (the two std::shared_ptr s point to the same struct).
In hindsight, given
make_shared
, wouldshared_ptr
have a constructor that takes a raw pointer had it been introduced with C++11?
What if you don't control the allocation of the object? What if you need to use a custom deleter? What if you need list-initialization instead of parens?
None of these cases is handled by make_shared
.
Additionally, if you're using weak_ptr
, a shared_ptr
allocated via make_shared
won't free any memory until all the weak_ptr
s are destroyed as well. So even if you have a normal shared pointer where none of the above apply, it's possible that you may still prefer the raw pointer constructor.
Yet another situation would be if your type provides overloads for operator new
and operator delete
. These may make it ill-suited for make_shared
, since those overloads will not be called - and presumably they exist for a reason.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With