问题
There are some functions in the STL which start with the make_
prefix like std::make_pair
, std::make_shared
, std::make_unique
etc. Why is it a better practice to use them instead of simply using the constructor ?
auto pair2 = std::pair< int, double >( 1, 2.0 );
auto pair3 = std::make_pair( 1, 2.0 );
std::shared_ptr< int > pointer1 = std::shared_ptr< int >( new int( 10 ) );
std::shared_ptr< int > pointer2 = std::make_shared< int >( 10 );
- I just see that these functions make the code a little shorter, but is that all ?
- Are there any other advantages ?
- Are these functions safer to use ?
回答1:
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.
回答2:
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 theshared_ptr
object in one go, allowing for lower allocation overhead and a likely better cache alignment.
回答3:
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.
来源:https://stackoverflow.com/questions/31232146/why-is-it-better-to-use-stdmake-instead-of-the-constructor