is it better to use shared_ptr.reset or operator =?

There is indeed a substantial difference between:

shared_ptr<T> sp(new T());

And:

shared_ptr<T> sp = make_shared<T>();

The first version performs an allocation for the T object, then performs a separate allocation to create the reference counter. The second version performs one single allocation for both the object and the reference counter, placing them in a contiguous region of memory, resulting in less memory overhead.

Also, some implementations are able to perform further space optimizations in the case of make_shared<> (see the “We Know Where You Live” optimization done by MS’s implementation).

However, that is not the only reason why make_shared<> exists. The version based on explicit new T() is not exception-safe in some situations, especially when invoking a function that accepts a shared_ptr.

void f(shared_ptr<T> sp1, shared_ptr<T> sp2);

...

f(shared_ptr<T>(new T()), shared_ptr<T>(new T()))

Here, the compiler could evaluate the first new T() expression, then evaluate the second new T() expression, then construct the corresponding shared_ptr<> objects. But what if the second allocation causes an exception before the first allocated object is bound to its shared_ptr<>? It will be leaked. With make_shared<>(), this is not possible:

f(make_shared<T>(), make_shared<T>())

Because allocated objects are bound to the respective shared_ptr<> objects inside each function call to make_shared<>(), this call is exception-safe. This is yet another reason why naked new should never be used unless you really know what you are doing. (*)

Considering your remark about reset(), you are right in observing that reset(new T()) will perform separate allocations for the counter and the object, just as the construction of a new shared_ptr<> will perform a separate allocation when a raw pointer is passed as an argument. Therefore, an assignment using make_shared<> is preferable (or even a statement such as reset(make_shared<T>())).

Whether or not reset() should support a variadic argument list, this is probably more of a kind of open discussion for which StackOverflow is not a good fit.

(*) There are a few situations that still require it. For instance, the fact that the C++ Standard Library lacks a corresponding make_unique<> function for unique_ptr, so you’ll have to write one yourself. Another situation is when you do not want the object and the counter to be allocated on a single memory block, because the presence of weak pointers to the object will prevent the entire block from being deallocated, even though no more owning pointers to the object exist.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)