Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any situation in which I wouldn't use std::make_shared?

From the research I have done, it sounds like std::make_shared is the preferred way of constructing a std::shared_ptr. Specifically because:

  1. It performs only one memory allocation, compared with using new, which performs at least two.
  2. If the ctor passed to make_shared throws, then it won't leak, as it will with new.

My question is, assuming that I want a shared_ptr, should I always use make_shared, or are there cases where new is preferred?

like image 921
Justin R. Avatar asked Oct 07 '13 18:10

Justin R.


People also ask

Should I use make_shared?

make_shared is exception-safe. It uses the same call to allocate the memory for the control block and the resource, which reduces the construction overhead. If you don't use make_shared , then you have to use an explicit new expression to create the object before you pass it to the shared_ptr constructor.

Why is make_shared more efficient?

One reason is because make_shared allocates the reference count together with the object to be managed in the same block of memory.

What is the difference between make_shared and shared_ptr?

The difference is that std::make_shared performs one heap-allocation, whereas calling the std::shared_ptr constructor performs two.

Should you use shared_ptr?

Use shared_ptr if you want to share ownership of a resource. Many shared_ptr can point to a single resource. shared_ptr maintains reference count for this propose. when all shared_ptr's pointing to resource goes out of scope the resource is destroyed.


2 Answers

As the counter and the object share the same allocation, they also share the same deallocation.

The counter has to persist until the last shared_ptr and weak_ptr go away. If you have a large object (or many small objects) with long-lasting weak_ptrs, this can cause memory contention if you allocate the shared_ptrs via make_shared.

Second, if you have a 3rd party API that hands you a pointer or a resource handle, and possibly has its own dispose functionality, make_shared is neither appropriate nor possible to use in every case. Creating your own make_ functions can keep the messy details out of the way lets you deal with this problem, and deals with the exception corner case as well.

Finally, while shared pointers are awesome, they are also overly powerful. Quite often I want a unique_ptr or even a boost::scoped_ptr, or an intrusive reference counting pointer, or the like to represent ownership. shared_ptr should be used only when the situation actually involves shared ownership of the resource: using it willy nilly because it is "easy" tends to end up with the resource equivalent of spaghetti code.

like image 113
Yakk - Adam Nevraumont Avatar answered Sep 20 '22 17:09

Yakk - Adam Nevraumont


You may have to deal with legacy code which returns a dynamically allocated object. In which case, you would need to use the std::shared_ptr<T> ctor with the pointer parameter. It's not preferable to using std::make_shared but it does allow you to use all the std::shared_ptr<T> goodness with legacy code.

I know that this is not strictly equivalent to using the std::shared_ptr<T> ctor with new directly but it is a valid use case of std::shared_ptr<T> where make_shared cannot be utilised.

like image 40
Gearoid Murphy Avatar answered Sep 23 '22 17:09

Gearoid Murphy