There are some functions in the STL which start with the make_
prefix like std::make_pair
, std::make_shared
, std::make_unique
Although it may be subjective, one main touted benefit for this technique is:
write code against interfaces, not implementations
In essence, function template instantiation performs type deduction based on the arguments you pass, whereas class template instantiation does not. As a consequence, you wouldn't have to pass template arguments as you would when instantiating the class directly.
It should be noted though, that this is not about "saving a few characters", but rather about making your code more general, and avoiding being tied to a concrete type in your function call.
However, this is not always the case, as your std::make_shared
example showed, there are still cases in which you have to pass the type as a template argument. But, as Herb Sutter points out, there are several other advantages when it comes to using std::make_shared
:
You should write for clarity and correctness first, and std::make_shared
achieves both of those (subjective, but I agree)
using std::make_shared
is more efficient, because it allocates your object as well as the shared_ptr
object in one go, allowing for lower allocation overhead and a likely better cache alignment.
make_unique
hides from you "raw" pointer, what's usually a good thing - it's less error prone.
make_shared
may improve memory allocation for shared_ptr<X>
instances. Normally when you use shared_ptr<X>
constructor it will allocate memory twice, first for instance of X
and second for it's internal data (e.g. reference counter). make_shared
enables optimization - it will create single, internal structure comprising both X
and reference counter, hence it will perform single memory allocation. And same as before it hides raw pointers.
Aside from the benefit of enabling argument deduction (as already mentioned in other answers), there are also some other benefits.
std::make_pair<T1, T2>
takes care to not simply return std::pair<T1, T2>
. If you pass in a value using std::ref
, then the returned pair won't store a std::reference_wrapper
, it will store a reference.
std::make_shared
can combine allocations. shared_ptr
needs some place to hold things like the refcount, weak pointer list, etc. that cannot be stored in the shared_ptr
directly. These can be combined with the object being created, in one slightly larger block rather than in two separate blocks.
std::make_shared
and std::make_unique
both make sure that no object gets left behind if exceptions are thrown. If you call a function as f(std::shared_ptr<int>(new int), std::shared_ptr<int>(new int))
, then it's possible the compiler first allocates two int
objects, and then constructs two shared_ptr<int>
objects. If the second allocation fails, and no shared_ptr<int>
object is set up yet to release the memory on destruction, then you have a memory leak. std::make_shared
and std::make_unique
combine the allocation of int
and the construction of std::shared_ptr<int>
in a function call, and the other allocation of int
and the other construction of std::shared_ptr<int>
in another function call. Function calls cannot overlap, so if the second allocation fails, there is already a shared pointer that will be destroyed, undoing the first allocation as well.