220

Why is there no std::make_unique function template in the standard C++11 library? I find

std::unique_ptr<SomeUserDefinedType> p(new SomeUserDefinedType(1, 2, 3));

a bit verbose. Wouldn't the following be much nicer?

auto p = std::make_unique<SomeUserDefinedType>(1, 2, 3);

This hides the new nicely and only mentions the type once.

Anyway, here is my attempt at an implementation of make_unique:

template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

It took me quite a while to get the std::forward stuff to compile, but I'm not sure if it's correct. Is it? What exactly does std::forward<Args>(args)... mean? What does the compiler make of that?

Xeo
  • 123,374
  • 44
  • 277
  • 381
fredoverflow
  • 237,063
  • 85
  • 359
  • 638
  • 1
    Pretty sure we've had this discussion before... also note that `unique_ptr` takes a second template parameter which you should somehow allow for - that's different from `shared_ptr`. – Kerrek SB Aug 12 '11 at 09:49
  • Perhaps it's because it's rather easy to write yourself? While a `make_unique()` simply wraps a `new` statement, it's not like `make_shared()` which is actually not trivial to implement correctly (it allocates the space for the reference count and the object at the same time). But good question though. – In silico Aug 12 '11 at 09:52
  • 5
    @Kerrek: I don't think it would make sense to parameterize `make_unique` with a custom deleter, because obviously it allocates via plain old `new` and hence *must* use plain old `delete` :) – fredoverflow Aug 12 '11 at 10:24
  • 1
    @Fred: That's true. So, the proposed `make_unique` would be limited to `new` allocation... well, it's fine if you want to write it, but I can see why something like that isn't part of the standard. – Kerrek SB Aug 12 '11 at 10:31
  • 4
    Actually, I like to use a `make_unique` template since the constructor of `std::unique_ptr` is explicit, and thus it is verbose to return `unique_ptr` from a function. Also, I'd rather use `auto p = make_unique(bar, baz)` than `std::unique_ptr p(new foo(bar, baz))`. – Alexandre C. Aug 12 '11 at 10:38
  • As alternative you can write p.reset( new SomeUserDefinedType(1, 2, 3) ); – innochenti Mar 15 '12 at 20:16
  • 5
    `make_unique` is coming in `C++14`, see http://isocpp.org/blog/2013/04/trip-report-iso-c-spring-2013-meeting – stefan May 09 '13 at 10:18

6 Answers6

159

Herb Sutter, chair of the C++ standardization committee, writes on his blog:

That C++11 doesn’t include make_unique is partly an oversight, and it will almost certainly be added in the future.

He also gives an implementation that is identical with the one given by the OP.

Edit: std::make_unique now is part of C++14.

Ivan Perevezentsev
  • 66
  • 1
  • 2
  • 11
Johan Råde
  • 18,399
  • 19
  • 62
  • 103
  • 2
    A `make_unique` function template does not itself guarantee exception safe calls. It relies on convention, that the caller uses it. In contrast, strict static type checking (which is the main diff between C++ and C) is built on the idea of *enforcing* safety, via types. And for that, `make_unique` can simply be a class instead of function. For example, see my [blog article](http://alfps.wordpress.com/2010/05/15/cppx-c98-constructor-arguments-forwarding-v2-posting/#0x_standard_forwarding_example) from May 2010. It's also linked to from the discussion on Herb's blog. – Cheers and hth. - Alf May 12 '12 at 13:42
  • @Cheersandhth.-Alf - I don't quite follow your comment. How is `make_unique` not exception safe? How would making it a class make it more exception safe? Inheriting from a class that is not designed to be derived does not seem like a good idea to me at any rate... – David Rodríguez - dribeas Jul 16 '12 at 00:49
  • 1
    @DavidRodríguez-dribeas: read Herb's blog to understand the exception safety issue. forget about "not designed to be derived", that's just rubbish. instead of my suggestion of making `make_unique` a class, i now think it's better to make it a function that produces a `make_unique_t`, the reason for that is a problem with the most perverse parse :-). – Cheers and hth. - Alf Jul 16 '12 at 07:14
  • 1
    @Cheersandhth.-Alf: Maybe we have read a different article, because the one I just [read](http://herbsutter.com/gotw/_102) clearly states that `make_unique` offers the strong exception guarantee. Or maybe you are mixing the tool with its use, in which case **no** function is exception safe. Consider `void f( int *, int* ){}`, clearly offers the `no throw` guarantee, but by your line of reasoning it is not exception safe, as it can be misused. Worse, `void f( int, int ) {}` is not exception safe either!: `typedef unique_ptr up; f( *up(new int(5)), *up(new int(10)))`... – David Rodríguez - dribeas Jul 16 '12 at 13:07
  • @DavidRodríguez-dribeas: it seems your point is that nothing is exception safe because everything can be abused so that it is *involved* in some exception unsafe code, and secondly, also that nothing is exception unsafe because it can theoretically be used in exception safe ways, and third, that by the authority of the article you refer to, `make_unique` magically confers exception safety on code where it can be applied. sorry, you fail to convince me. as i see it none of your three points are valid logic, and they're also a bit mutually contradictory. – Cheers and hth. - Alf Jul 16 '12 at 18:49
  • @David: anyway, i fail to see the utility of not having a more safe to use `make_unique` function. why are you arguing that it should be more risky? – Cheers and hth. - Alf Jul 16 '12 at 18:58
  • 2
    @Cheersandhth.-Alf: I asked about the exception issues *in* `make_unique` implemented as above and you point me to an article by Sutter, the article that my google-fu pointed me to states that `make_unique` offers the *strong exception guarantee*, which contradicts your statement above. If you have a different article I **am** interested in reading it. So my original question stands *How is `make_unique` (as defined above) not exception safe?* (Sidenote: yes, I do think that `make_unique` *improves* exception safety in places where it can be applied) – David Rodríguez - dribeas Jul 16 '12 at 19:09
  • 3
    ... also I am not pursuing a less safe to use `make_unique` function. First I don't see how this one is unsafe, and I don't see how adding an extra type would make it *safer*. What I do know is that I am interested in *understanding* the issues that this implementation can have --I cannot see any--, and how an alternative implementation would solve them. What are the *conventions* that `make_unique` depends on? How would you use type checking to enforce safety? Those are the two questions for which I would love an answer. – David Rodríguez - dribeas Jul 16 '12 at 19:16
  • 1
    @David: well, ok. first, the exception safety issue is *not* about `make_unique`. it is about the natural use of a function declared with two or more `unique_ptr` args. `make_unique` is just one tool that a user of such an unsafe function can use to make a call safe. the user can also do that in other ways, but still the function is unsafe in the original way: it requires some deep understanding to write more to make calls safe. instead the formal arguments can be of a type that *requires* use of `make_unique`, or some explicit passing of ownership of existing objects. that's far more robust. – Cheers and hth. - Alf Jul 16 '12 at 19:30
  • 1
    @Cheersandhth.-Alf: Ok, so what you propose is changing the interface to take a `make_unique_t` that forces the use of `make_unique` and internally holds the `unique_ptr` to ensure that callers *will* use `make_unique` which is *safe*. Initially I understood that you claimed `make_unique` not to be/make the call exception safe. Regarding this extra type, the problem is that you will then limit the uses of your function to memory that has been just allocated which would limit usability (alternatively provide a `make_unique` variant that is able to move from an already constructed `unique_ptr`) – David Rodríguez - dribeas Jul 16 '12 at 19:44
  • yes, roughly. as i wrote, some "explicit passing of ownership" must be supported. as i didn't write, there's not so much space in these comments, `make_unique_ptr_t` is most naturally a class derived from `unique_ptr`, and then it just has a `unique_ptr` base class sub-object and adds no possible overhead -- i.e., it's *gratis*. – Cheers and hth. - Alf Jul 16 '12 at 20:02
  • @hyde: The link was to the *solution* to the Guru of the Week Problem #102, http://herbsutter.com/2011/12/02/gotw-102-exception-safe-function-calls-difficulty-710/. The solution seems to have been removed from the site. – Johan Råde Jun 02 '13 at 09:43
80

Nice, but Stephan T. Lavavej (better known as STL) has a better solution for make_unique, which works correctly for the array version.

#include <memory>
#include <type_traits>
#include <utility>

template <typename T, typename... Args>
std::unique_ptr<T> make_unique_helper(std::false_type, Args&&... args) {
  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

template <typename T, typename... Args>
std::unique_ptr<T> make_unique_helper(std::true_type, Args&&... args) {
   static_assert(std::extent<T>::value == 0,
       "make_unique<T[N]>() is forbidden, please use make_unique<T[]>().");

   typedef typename std::remove_extent<T>::type U;
   return std::unique_ptr<T>(new U[sizeof...(Args)]{std::forward<Args>(args)...});
}

template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
   return make_unique_helper<T>(std::is_array<T>(), std::forward<Args>(args)...);
}

This can be seen on his Core C++ 6 video.

An updated version of STL's version of make_unique is now available as N3656. This version got adopted into draft C++14.

Bruno De Fraine
  • 39,825
  • 8
  • 50
  • 62
tominator
  • 801
  • 6
  • 2
  • make_unique is been proposed by Stephen T Lavalej into the next std update. – tominator Nov 25 '12 at 11:52
  • Here is a like to him talking about adding it. http://channel9.msdn.com/Series/C9-Lectures-Stephan-T-Lavavej-Core-C-/STLCCSeries6#c634889372900373011 – tominator Nov 25 '12 at 11:59
  • why make all the unnecessary edits xeo, it was fine as it was. That code was as exactly as Stephen T. Lavalej put it, and he works for dinkumware which maintains the std library. You've already commented on that wall, so you should know. – tominator Nov 25 '12 at 22:28
  • 3
    The implementation for `make_unique` should go in a header. Headers should not import a namespace (see Item #59 in Sutter/Alexandrescu's "C++ Coding Standards" book). Xeo's changes help avoid encouraging bad practices. – Bret Kuhns Dec 15 '12 at 01:33
  • unfortunately, not supported by VC2010, even VC2012 I think, which both not support varidic tempalte parameter – zhaorufei Jan 08 '13 at 10:23
  • This implementation is now in VC2013, which has new been released. It will also be included in the latest version of other C++ IDE's that allow C++13. – tominator Nov 23 '13 at 11:15
19

While nothing stops you from writing your own helper, I believe that the main reason for providing make_shared<T> in the library is that it actually creates a different internal type of shared pointer than shared_ptr<T>(new T), which is differently allocated, and there's no way to achieve this without the dedicated helper.

Your make_unique wrapper on the other hand is mere syntactic sugar around a new expression, so while it might look pleasing to the eye, it doesn't bring anything new to the table. Correction: this isn't in fact true: Having a function call to wrap the new expression provides exception safety, for example in the case where you call a function void f(std::unique_ptr<A> &&, std::unique_ptr<B> &&). Having two raw news that are unsequenced with respect to one another means that if one new expression fails with an exception, the other may leak resources. As for why there's no make_unique in the standard: It was just forgotten. (This happens occasionally. There's also no global std::cbegin in the standard even though there should be one.)

Also note that unique_ptr takes a second template parameter which you should somehow allow for; this is different from shared_ptr, which uses type erasure to store custom deleters without making them part of the type.

Kerrek SB
  • 428,875
  • 83
  • 813
  • 1,025
  • What exactly do you mean by "different *internal* type"? – fredoverflow Aug 12 '11 at 10:04
  • 1
    @FredOverflow: The shared pointer is a relatively complicated class; internally it keeps a polymorphic reference control block, but there are several different kinds of control blocks. `shared_ptr(new T)` uses one of them, `make_shared()` uses a different one. Allowing that is a Good Thing, and the make-shared version is in some sense the lightest-weight shared pointer you can get. – Kerrek SB Aug 12 '11 at 10:11
  • 15
    @FredOverflow: `shared_ptr` allocates a block of dynamic memory to keep up the count and the "disposer" action when you create a `shared_ptr`. If you pass the pointer explicitly, it needs creating a "new" block, if you use `make_shared` it can bundle *your* object and the satellite data in a single block of memory (one `new`) resulting in faster allocation/deallocation, less fragmentation, and (normally) better cache behavior. – Matthieu M. Aug 12 '11 at 10:17
  • 2
    I think I need to re-watch [shared_ptr and friends](http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-Lavavej-Advanced-STL-1-of-n)... – fredoverflow Aug 12 '11 at 10:18
  • @FredOverflow: `shared_ptr` is the only strange beast, because of this extraneous information it needs to track (count and deleter). The others are, thankfully, much simpler to grok. – Matthieu M. Aug 12 '11 at 10:24
  • @Matthieu: Indeed, `unique_ptr` is a far lighter-weight class -- I would say that `make_shared` is as close in concept to `unique_ptr` as you can get, only that it uses an allocator rather than letting the user pick the allocation function. – Kerrek SB Aug 12 '11 at 10:33
  • 4
    -1 "Your make_unique wrapper on the other hand is mere syntactic sugar around a new expression, so while it might look pleasing to the eye, it doesn't bring anything new to the table." is wrong. It brings the possibility of exception safe function invocation. It does not bring a guarantee, however; for that, it would need to be class so that the formal arguments could be declared of that class (Herb described that as the difference between opt-in and opt-out). – Cheers and hth. - Alf May 12 '12 at 13:16
  • 1
    @Cheersandhth.-Alf: Yeah, that's true. I've since realised this. I'll edit the answer. – Kerrek SB May 12 '12 at 17:36
19

std::make_shared isn't just shorthand for std::shared_ptr<Type> ptr(new Type(...));. It does something that you cannot do without it.

In order to do its job, std::shared_ptr must allocate a tracking block in addition to holding the storage for the actual pointer. However, because std::make_shared allocates the actual object, it is possible that std::make_shared allocates both the object and the tracking block in the same block of memory.

So while std::shared_ptr<Type> ptr = new Type(...); would be two memory allocations (one for the new, one in the std::shared_ptr tracking block), std::make_shared<Type>(...) would allocate one block of memory.

That is important for many potential users of std::shared_ptr. The only thing a std::make_unique would do is be slightly more convenient. Nothing more than that.

Xeo
  • 123,374
  • 44
  • 277
  • 381
Nicol Bolas
  • 378,677
  • 53
  • 635
  • 829
13

In C++11 ... is used (in template code) for "pack expansion" too.

The requirement is that you use it as a suffix of an expression containing an unexpanded pack of parameters, and it will simply apply the expression to each of the elements of the pack.

For example, building on your example:

std::forward<Args>(args)... -> std::forward<int>(1), std::forward<int>(2),
                                                     std::forward<int>(3)

std::forward<Args...>(args...) -> std::forward<int, int, int>(1,2,3)

The latter being incorrect I think.

Also, pack of arguments may not be passed to a function unexpanded. I am unsure about a pack of template parameters.

Johan Råde
  • 18,399
  • 19
  • 62
  • 103
Matthieu M.
  • 251,718
  • 39
  • 369
  • 642
  • 1
    Nice to see this spelt out. Why not include the variadic template parameter, too? – Kerrek SB Aug 12 '11 at 11:55
  • @Kerrek: because I am not so sure about its strange syntax, and I don't know if many people have played with. So I'll keep to what I know. It may warrant a c++ FAQ entry, if someone was motivated and knowledgeable enough, for the variadic syntax is quite complete. – Matthieu M. Aug 12 '11 at 13:52
  • The syntax is `std::forward(args)...`, which expands to `forward(x1), forward(x2), ...`. – Kerrek SB Aug 12 '11 at 15:11
  • @Kerrek: Oh, I thought you were talking about pure type manipulations. I don't see the need to put the type here, the `T1`... would come from nowhere. – Matthieu M. Aug 12 '11 at 16:23
  • 1
    :I think `forward` actually always requires a template parameter, doesn't it? – Kerrek SB Aug 12 '11 at 16:39
  • @Kerrek: I don't think so, ideone seems to agree http://ideone.com/9cxH6 (but then, I would not take it at face value). – Matthieu M. Aug 12 '11 at 17:30
  • Hmmm, I'm not 100% on this, but if you don't specify the parameter, it might be that you're not getting what you intend -- i.e. the parameter might be derived wrongly. It'd still compile, but for instance you might force an rvalue to become an lvalue. I'm not sure though. – Kerrek SB Aug 12 '11 at 20:46
  • @Matthieu: If you don't specify the template parameter in `std::forward`, it will not compile. It was intentionally designed to error-out in this way. – Howard Hinnant Aug 12 '11 at 22:00
  • @Howard: thanks! Seems to be a gcc glitch on ideone then, I'll patch my example then :) – Matthieu M. Aug 13 '11 at 12:43
  • ideone may not have picked it up because you didn't instantiate `make_unique` in your example. – Howard Hinnant Aug 13 '11 at 14:32
  • 1
    @Howard: right! Forcing instantiation triggers the warning (http://ideone.com/GDNHb) – Matthieu M. Aug 14 '11 at 11:48
5

Inspired by the implementation by Stephan T. Lavavej, I thought it might be nice to have a make_unique that supported array extents, it's on github and I'd love to get comments on it. It allows you to do this:

// create unique_ptr to an array of 100 integers
auto a = make_unique<int[100]>();

// create a unique_ptr to an array of 100 integers and
// set the first three elements to 1,2,3
auto b = make_unique<int[100]>(1,2,3); 
Nathan Binkert
  • 8,088
  • 1
  • 26
  • 37