Are there any downsides with using make_shared to create a shared_ptr
Are there any downsides with using make_shared<T>()
instead of using shared_ptr<T>(new T)
.
Boost documentation states
There have been repeated requests from users for a factory function that creates an object of a given type and returns a shared_ptr to it. Besides convenience and style, such a function is also exception safe and considerably faster because it can use a single allocation for both the object and its corresponding control block, eliminating a significant portion of shared_ptr's construction overhead. This eliminates one of the major efficiency complaints about shared_ptr.
Solution 1:
In addition to the points presented by @deft_code, an even weaker one:
- If you use
weak_ptr
s that live after all theshared_ptr
s to a given object have died, then this object's memory will live in memory along with the control block until the last weak_ptr dies. In other words the object is destroyed but not deallocated until the lastweak_ptr
is destroyed.
Solution 2:
I know of at least two.
- You must be in control of the allocation. Not a big one really, but some older api's like to return pointers that you must delete.
- No custom deleter. I don't know why this isn't supported, but it isn't. That means your shared pointers have to use a vanilla deleter.
Pretty weak points. so try to always use make_shared.
Solution 3:
From http://www.codesynthesis.com/~boris/blog/2010/05/24/smart-pointers-in-boost-tr1-cxx-x0/
The other drawback of the make_shared() implementation is the increase in the object code size. Due to the way this optimization is implemented, an additional virtual table as well as a set of virtual functions will be instantiated for each object type that you use with make_shared().
Solution 4:
Additionally, make_shared
is not compatible with the factory pattern. This is because the call to make_shared
within your factory function calls the library code, which in turn calls new
, which it doesn't have access to, since it cannot call the class's private constructor(s) (constructor(s) should be private, if you follow the factory pattern correctly).
Solution 5:
With make shared you can not specify how allocation and deallocation of the held object will be done.
When that is desired, use std::allocate_shared<T>
instead:
std::vector<std::shared_ptr<std::string>> avec;
std::allocator<std::string> aAllocator;
avec.push_back(std::allocate_shared<std::string>(aAllocator,"hi there!"));
Note that the vector does not need to be informed about the allocator!
For making a custom allocator, have a look here https://stackoverflow.com/a/542339/1149664