35

Based on the answers in these questions here, I know that it is certainly preferred to use c++14's std::make_unique than to emplace_back(new X) directly.

That said, is it preferred to call

my_vector.push_back(std::make_unique<Foo>("constructor", "args"));

or

my_vector.emplace_back(std::make_unique<Foo>("constructor", "args"));

That is, should I use push_back or emplace_back when adding an std::unique_ptr constructed from std::make_unique?

==== EDIT ====

and why? c: <-- (tiny smile)

Community
  • 1
  • 1
NHDaly
  • 7,390
  • 4
  • 40
  • 45

2 Answers2

34

It doesn't make a difference as far as construction of the new object is concerned; you already have a unique_ptr<Foo> prvalue (the result of the call to make_unique) so both push_back and emplace_back will call the unique_ptr move constructor when constructing the element to be appended to the vector.

If your use case involves accessing the newly constructed element after insertion, then emplace_back is more convenient since C++17 because it returns a reference to the element. So instead of

my_vector.push_back(std::make_unique<Foo>("constructor", "args"));
my_vector.back().do_stuff();

you can write

my_vector.emplace_back(std::make_unique<Foo>("constructor", "args")).do_stuff();
Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • 1
    Yes agreed, that's why I asked. :) – NHDaly Mar 17 '15 at 01:15
  • 3
    Actually, there is a difference... `emplace_back()` returns a reference to the added element, whereas `push_back()` returns void. `emplace_back(std::make_unique<>())` is therefore useful in contexts where you need to use the object after it has been added. – j b Sep 19 '18 at 18:40
  • 2
    @JamieBullock Well, there was no difference when I answered the question 3 years ago. Updated the answer to include the C++17 change to the return type. Thanks. – Praetorian Sep 19 '18 at 19:45
1

Clearly

template<class T, class A, class...Args>
void push_unique( std::vector<std::unique_ptr<T>,A>& v, Args&&...args ) {
  v.push_back( std::make_unique<T>(std::forward<Args>(args)...) );
}

is the best option:

push_unique(my_vector,"constructor", "args");

sadly this is prefix notation: (operator, container, arguments...) vs infix (container operator arguments...).

If only there was a way to make it infix, like extension methods or named operators.

Because that would be cool.

Community
  • 1
  • 1
Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524