Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preferred way of creating shared pointers

The documentation states that std::make_shared<T> typically allocates memory for T and the smart pointer's control block at once in contrast to std::shared_pointer<T>(new T), which performs two allocations. Does it mean it is more efficient and therefore a one should always use std::make_shared if possible?

The same question about Qt equivalent - QSharedPointer. According to the docs the QSharedPointer internals and the object are allocated in one single memory allocation, which could help reduce memory fragmentation in a long-running application. Does it mean QSharedPointer<T>::create() is the preferred one?

class MyClass {};

QSharedPointer<MyClass> ptr1 = QSharedPointer<MyClass>::create();   // better
QSharedPointer<MyClass> ptr2(new MyClass);  // worse
like image 806
mentalmushroom Avatar asked Oct 06 '16 06:10

mentalmushroom


1 Answers

std::make_shared is preferred in almost every case. However, if you use weak pointers, you can easily get into a "memory leak" situation where memory is kept around far longer than you would think at first glance (after all shared_ptrs are gone).

As long as there is a std::weak_ptr associated with a std::shared_ptr control block, the control block must remain. Since std::make_shared creates a single memory allocation for both the control block and the data, if the control block remains, the data must remain, too. With std::shared_ptr, the there are two allocations, so they can be cleaned up independently.

So, if you're not using std::weak_ptr (additional caveats below), absolutely always prefer std::make_shared for benefits including the number of allocations and exception safety. If you are using std::weak_ptr, you must be much more thoughtful about your design.

Modern Effective C++ chapter 4 is dedicated to how/when to use different smart pointers. It's a concise book for existing c++ programmers to catch up on the new features in c++11/14, including smart pointers.

edit: as @midor mentions, you there is also simply no option to provide a custom deleter when using std::make_shared. Also, if the type T has different constructors that could be called with the same type but one with () and one with {}, then it will always prefer the one with (). For example std::make_shared<std::vector>(10,10) calls std::vector(10,10) not std::vector{10,10}.

like image 148
xaxxon Avatar answered Nov 03 '22 07:11

xaxxon