Why is it better to use std::make_* instead of the constructor?

前端 未结 3 967
我在风中等你
我在风中等你 2021-02-18 16:56

There are some functions in the STL which start with the make_ prefix like std::make_pair, std::make_shared, std::make_unique

相关标签:
3条回答
  • 2021-02-18 17:21

    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:

    1. You should write for clarity and correctness first, and std::make_shared achieves both of those (subjective, but I agree)

    2. 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.

    0 讨论(0)
  • 2021-02-18 17:21

    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.

    0 讨论(0)
  • 2021-02-18 17:45

    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.

    0 讨论(0)
提交回复
热议问题