Differences between std::make_unique and std::unique_ptr with new

73,614

Solution 1

The motivation behind make_unique is primarily two-fold:

  • make_unique is safe for creating temporaries, whereas with explicit use of new you have to remember the rule about not using unnamed temporaries.

    foo(make_unique<T>(), make_unique<U>()); // exception safe
    
    foo(unique_ptr<T>(new T()), unique_ptr<U>(new U())); // unsafe*
    
  • The addition of make_unique finally means we can tell people to 'never' use new rather than the previous rule to "'never' use new except when you make a unique_ptr".

There's also a third reason:

  • make_unique does not require redundant type usage. unique_ptr<T>(new T()) -> make_unique<T>()

None of the reasons involve improving runtime efficiency the way using make_shared does (due to avoiding a second allocation, at the cost of potentially higher peak memory usage).

* It is expected that C++17 will include a rule change that means that this is no longer unsafe. See C++ committee papers P0400R0 and P0145R3.

Solution 2

std::make_unique and std::make_shared are there for two reasons:

  1. So that you don't have to explicitly list the template type arguments.
  2. Additional exception safety over using std::unique_ptr or std::shared_ptr constructors. (See the Notes section here.)

It's not really about runtime efficiency. There is the bit about the control block and the T being allocated all at once, but I think that's more a bonus and less a motivation for these functions to exist.

Solution 3

A reason why you would have to use std::unique_ptr(new A()) or std::shared_ptr(new A()) directly instead of std::make_*() is being unable to access the constructor of class A outside of current scope.

Solution 4

Consider function call

void function(std::unique_ptr<A>(new A()), std::unique_ptr<B>(new B())) { ... }

Suppose that new A() succeeds, but new B() throws an exception: you catch it to resume the normal execution of your program. Unfortunately, the C++ standard does not require that object A gets destroyed and its memory deallocated: memory silently leaks and there's no way to clean it up. By wrapping A and B into std::make_uniques you are sure the leak will not occur:

void function(std::make_unique<A>(), std::make_unique<B>()) { ... }

The point here is that std::make_unique<A> and std::make_unique<B> are now temporary objects, and cleanup of temporary objects is correctly specified in the C++ standard: their destructors will be triggered and the memory freed. So if you can, always prefer to allocate objects using std::make_unique and std::make_shared.

Share:
73,614

Related videos on Youtube

NFRCR
Author by

NFRCR

Updated on December 03, 2020

Comments

  • NFRCR
    NFRCR over 3 years

    Does std::make_unique have any efficiency benefits like std::make_shared?

    Compared to manually constructing std::unique_ptr:

    std::make_unique<int>(1);         // vs
    std::unique_ptr<int>(new int(1));
    
    • Ed Heal
      Ed Heal about 10 years
      Does make_shared have any efficiency over just writing the long hand code?
    • bames53
      bames53 about 10 years
      @EdHeal It may, because make_shared can allocate both the space for the object and the space for the control block together in a single allocation. The cost of that is that the object cannot be deallocated separately from the control block, so if you use weak_ptr a lot then you may end up using more memory.
    • Ed Heal
      Ed Heal about 10 years
      Perhaps this is a good starting point stackoverflow.com/questions/9302296/…
    • Krishna Kanth Yenumula
      Krishna Kanth Yenumula almost 3 years
      See this link for detailed explanation: herbsutter.com/gotw/_102
  • David G
    David G about 10 years
    They're also there for exception-safety.
  • Timothy Shields
    Timothy Shields about 10 years
    @0x499602D2 And that, good addition. This page talks about that.
  • Timothy Shields
    Timothy Shields about 10 years
    It would make more sense to say std::unique_ptr and std::shared_ptr are why we can tell people to "never use new."
  • bames53
    bames53 about 10 years
    @TimothyShields Yeah, that's what I mean. It's just that in C++11 we have make_shared and so make_unique is the final piece that was previously missing.
  • Dan Nissenbaum
    Dan Nissenbaum about 8 years
    Any way you could mention briefly, or link to, the reason for not using unnamed temporaries?
  • Dan Nissenbaum
    Dan Nissenbaum about 8 years
    Actually, from stackoverflow.com/a/19472607/368896, I've got it... From that answer, consider the following function call f: f(unique_ptr<T>(new T), function_that_can_throw()); - to quote the answer: The compiler is allowed to call (in order): new T, function_that_can_throw(), unique_ptr<T>(...). Obviously if function_that_can_throw actually throws then you leak. make_unique prevents this case. So, my question is answered.
  • Daniel
    Daniel over 7 years
    @bames53 Unfortunately there is still need to use raw new if you want to pass a custom facet to std::locale (overload 7).
  • tambre
    tambre about 7 years
    @bames53 Have there been any news regarding the footnote?
  • bames53
    bames53 about 7 years
    @tambre The linked papers are part of the C++17 draft, and there shouldn't be any significant changes between now and publication later this year. Clang already implements these rules. It's not clear from gcc's status page if they do or not yet.
  • Passer By
    Passer By almost 7 years
    Took a really long time to see why it is now safe, but yeah it is. BTW thanks for updating your answer
  • Patrick
    Patrick almost 5 years
    One reason I once had to use std::unique_ptr<T>(new T()) was because the constructor of T was private. Even if the call to std::make_unique was in a public factory method of class T, it didn't compile because one of the underlying methods of std::make_unique could not access the private constructor. I didn't want to make that method friend because I didn't want to rely on the implementation of std::make_unique. So the only solution was, calling new in my factory method of class T, and then wrap it in an std::unique_ptr<T>.
  • MathBunny
    MathBunny over 4 years
    For future readers, C++17 does not allow for interleaving of function arguments so the argument for exception-safety doesn't hold anymore. The memory allocation for two parallel std::make_shared will ensure that at least one of them gets wrapped in the smart pointer before the other memory allocation occurs, hence no leaks.
  • nyanpasu64
    nyanpasu64 over 2 years
    Is there a plan to fix C++ so make_unique and make_shared can access private constructors?
  • Volodymyr Lashko
    Volodymyr Lashko over 2 years
    @nyanpasu64 make_unique needs no fixing. You can always make it a friend of your class with a private constructor.