push_back vs emplace_back

C++Visual Studio-2010StlC++11Move Semantics

C++ Problem Overview


I'm a bit confused regarding the difference between push_back and emplace_back.

void emplace_back(Type&& _Val);
void push_back(const Type& _Val);
void push_back(Type&& _Val);

As there is a push_back overload taking a rvalue reference I don't quite see what the purpose of emplace_back becomes?

C++ Solutions


Solution 1 - C++

In addition to what visitor said :

The function void emplace_back(Type&& _Val) provided by MSCV10 is non conforming and redundant, because as you noted it is strictly equivalent to push_back(Type&& _Val).

But the real C++0x form of emplace_back is really useful: void emplace_back(Args&&...);

Instead of taking a value_type it takes a variadic list of arguments, so that means that you can now perfectly forward the arguments and construct directly an object into a container without a temporary at all.

That's useful because no matter how much cleverness RVO and move semantic bring to the table there is still complicated cases where a push_back is likely to make unnecessary copies (or move). For example, with the traditional insert() function of a std::map, you have to create a temporary, which will then be copied into a std::pair<Key, Value>, which will then be copied into the map :

std::map<int, Complicated> m;
int anInt = 4;
double aDouble = 5.0;
std::string aString = "C++";
    
// cross your finger so that the optimizer is really good
m.insert(std::make_pair(4, Complicated(anInt, aDouble, aString))); 

// should be easier for the optimizer
m.emplace(4, anInt, aDouble, aString);

So why didn't they implement the right version of emplace_back in MSVC? Actually, it bugged me too a while ago, so I asked the same question on the Visual C++ blog. Here is the answer from Stephan T Lavavej, the official maintainer of the Visual C++ standard library implementation at Microsoft.

> Q: Are beta 2 emplace functions just some kind of placeholder right now? > > A: As you may know, variadic templates > aren't implemented in VC10. We > simulate them with preprocessor > machinery for things like > make_shared<T>(), tuple, and the new > things in <functional>. This > preprocessor machinery is relatively > difficult to use and maintain. Also, > it significantly affects compilation > speed, as we have to repeatedly > include subheaders. Due to a > combination of our time constraints > and compilation speed concerns, we > haven't simulated variadic templates > in our emplace functions. > > When variadic templates are > implemented in the compiler, you can > expect that we'll take advantage of > them in the libraries, including in > our emplace functions. We take > conformance very seriously, but > unfortunately, we can't do everything > all at once.

It's an understandable decision. Everyone who tried just once to emulate variadic template with preprocessor horrible tricks knows how disgusting this stuff gets.

Solution 2 - C++

emplace_back shouldn't take an argument of type vector::value_type, but instead variadic arguments that are forwarded to the constructor of the appended item.

template <class... Args> void emplace_back(Args&&... args); 

It is possible to pass a value_type which will be forwarded to the copy constructor.

Because it forwards the arguments, this means that if you don't have rvalue, this still means that the container will store a "copied" copy, not a moved copy.

 std::vector<std::string> vec;
 vec.emplace_back(std::string("Hello")); // moves
 std::string s;
 vec.emplace_back(s); //copies

But the above should be identical to what push_back does. It is probably rather meant for use cases like:

 std::vector<std::pair<std::string, std::string> > vec;
 vec.emplace_back(std::string("Hello"), std::string("world")); 
 // should end up invoking this constructor:
 //template<class U, class V> pair(U&& x, V&& y);
 //without making any copies of the strings

Solution 3 - C++

Optimization for emplace_back can be demonstrated in next example.

For emplace_back constructor A (int x_arg) will be called. And for push_back A (int x_arg) is called first and move A (A &&rhs) is called afterwards.

Of course, the constructor has to be marked as explicit, but for current example is good to remove explicitness.

#include <iostream>
#include <vector>
class A
{
public:
  A (int x_arg) : x (x_arg) { std::cout << "A (x_arg)\n"; }
  A () { x = 0; std::cout << "A ()\n"; }
  A (const A &rhs) noexcept { x = rhs.x; std::cout << "A (A &)\n"; }
  A (A &&rhs) noexcept { x = rhs.x; std::cout << "A (A &&)\n"; }

private:
  int x;
};

int main ()
{
  {
    std::vector<A> a;
    std::cout << "call emplace_back:\n";
    a.emplace_back (0);
  }
  {
    std::vector<A> a;
    std::cout << "call push_back:\n";
    a.push_back (1);
  }
  return 0;
}

output:

call emplace_back:
A (x_arg)

call push_back:
A (x_arg)
A (A &&)

Solution 4 - C++

One more example for lists:

// constructs the elements in place.                                                
emplace_back("element");

// creates a new object and then copies (or moves) that object.
push_back(ExplicitDataType{"element"});

Solution 5 - C++

Specific use case for emplace_back: If you need to create a temporary object which will then be pushed into a container, use emplace_back instead of push_back. It will create the object in-place within the container.

Notes:

  1. push_back in the above case will create a temporary object and move it into the container. However, in-place construction used for emplace_back would be more performant than constructing and then moving the object (which generally involves some copying).
  2. In general, you can use emplace_back instead of push_back in all the cases without much issue. (See exceptions)

Solution 6 - C++

A nice code for the push_back and emplace_back is shown here.

http://en.cppreference.com/w/cpp/container/vector/emplace_back

You can see the move operation on push_back and not on emplace_back.

Solution 7 - C++

emplace_back conforming implementation will forward arguments to the vector<Object>::value_typeconstructor when added to the vector. I recall Visual Studio didn't support variadic templates, but with variadic templates will be supported in Visual Studio 2013 RC, so I guess a conforming signature will be added.

With emplace_back, if you forward the arguments directly to vector<Object>::value_type constructor, you don't need a type to be movable or copyable for emplace_back function, strictly speaking. In the vector<NonCopyableNonMovableObject> case, this is not useful, since vector<Object>::value_type needs a copyable or movable type to grow.

But note that this could be useful for std::map<Key, NonCopyableNonMovableObject>, since once you allocate an entry in the map, it doesn't need to be moved or copied ever anymore, unlike with vector, meaning that you can use std::map effectively with a mapped type that is neither copyable nor movable.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionronagView Question on Stackoverflow
Solution 1 - C++Thomas PetitView Answer on Stackoverflow
Solution 2 - C++visitorView Answer on Stackoverflow
Solution 3 - C++vadikrobotView Answer on Stackoverflow
Solution 4 - C++user3847351View Answer on Stackoverflow
Solution 5 - C++vaibhav kumarView Answer on Stackoverflow
Solution 6 - C++DharmaView Answer on Stackoverflow
Solution 7 - C++Germán DiagoView Answer on Stackoverflow