51

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.

Tobias Furuholm
  • 4,727
  • 4
  • 30
  • 39
  • 6
    One might wonder, what are the other major efficiency complaints about shared_ptr? – Viktor Sehr Aug 18 '11 at 06:50
  • Exception safety is a pretty strong *asset* of `std::make_shared`. Try to use it whenever possible. – Alexandre C. Dec 25 '12 at 11:41
  • @ViktorSehr Mutex locks on the reference counter when a `shared_ptr` is copied mainly :) – Drax Oct 01 '14 at 14:07
  • @Drax: Ah, so theyre thread safe? Didnt know that – Viktor Sehr Oct 01 '14 at 18:37
  • @Drax Dont mind the questionmark btw, I can google :) – Viktor Sehr Oct 01 '14 at 18:40
  • @ViktorSehr [cppreference](http://en.cppreference.com/w/cpp/memory/shared_ptr) says: `All member functions (including copy constructor and copy assignment) can be called by multiple threads on different instances of shared_ptr without additional synchronisation even if these instances are copies and share ownership of the same object.` Which means that the shared data has some kind of synchronisation. (AFAIK implementations usually use atomic operations to increment the counter which make them less performance eaters) – Drax Oct 02 '14 at 08:02

5 Answers5

38

In addition to the points presented by @deft_code, an even weaker one:

  • If you use weak_ptrs that live after all the shared_ptrs 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 last weak_ptr is destroyed.
deft_code
  • 57,255
  • 29
  • 141
  • 224
sbk
  • 9,212
  • 4
  • 32
  • 40
  • 1
    That's also the case if you don't use `make_shared`. The only difference is that the control block will be in a separately allocated lump of memory. – Mike Seymour Jan 27 '10 at 17:36
  • 13
    @Mike: surely not - normally, if there are no shared_ptrs to the object, only weak_ptrs, then the object is deleted immediately. I don't know off-hand whether the control block remains, I'll take your word for it. With make_shared, the control block and the object co-habit a single allocation, so if the memory for one of them remains then both do (although I'd guess the object is destructed, just the memory not freed?). – Steve Jessop Jan 27 '10 at 20:53
  • 3
    Er, yeah. Sorry. I must have had my other brain in when I wrote that. – Mike Seymour Jan 28 '10 at 01:01
26

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.

deft_code
  • 57,255
  • 29
  • 141
  • 224
  • 6
    There's no custom deleter because only `make_shared` itself knows how to delete the object. – Mike Seymour Jan 27 '10 at 17:39
  • 4
    The custom deleter is used to do some interesting tricks not limited to just deleting, which is why deft_code mentioned it. – Catskul Jan 25 '12 at 01:47
  • If you could add a custom deleter, then you should have the ability for a custom allocator as well; let's say that it would complicate the interface too much. – ipapadop Sep 12 '12 at 22:46
  • @ipapadop: I don't follow -- the allocation has already happened by that point and doesn't need to happen again, so there's no need to keep an allocator function around. (Either you've passed an already-allocated pointer to the `shared_ptr` ctor, or you've asked `make_shared()` to do the allocation for you.) – j_random_hacker Oct 11 '12 at 14:55
  • 2
    @MikeSeymour: From `shared_ptr`'s point of view, yes, it needs to have a custom deleter furnished by `make_shared()`, but it would be possible and perhaps useful to provide the caller of `make_shared()` with the ability to run a custom "sub-deleter" that gets run from inside `make_shared()`'s own custom deleter. – j_random_hacker Oct 11 '12 at 14:58
  • 2
    What I'm saying is that it would look something like this: `template shared_ptr make_shared2(Allocator a, Deleter d, Args... args);` Yes, it could be provided, but it's not very pretty. – ipapadop Oct 11 '12 at 21:26
  • @ipapadop: It makes sense now, thanks. (You can still overload `operator new` as a workaround, but I realise that doesn't give you per-allocation control). – j_random_hacker Oct 11 '12 at 23:54
  • @ipapadop sounds like you want std::allocate_shared . – Pedro Lamarão Jun 14 '14 at 01:08
  • @PedroLamarão yes, but you have to write a class conforming to the Allocator concept, which is a few lines of code. See for example the shared_ptr constructor that takes both a Deleter and an Allocator (http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr). – ipapadop Jun 14 '14 at 21:56
14

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().

Viktor Sehr
  • 12,825
  • 5
  • 58
  • 90
8

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).

Rok Strniša
  • 6,781
  • 6
  • 41
  • 53
7

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

Community
  • 1
  • 1
Johan Lundberg
  • 26,184
  • 12
  • 71
  • 97