Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficiency of C++11 push_back() with std::move versus emplace_back() for already constructed objects

In C++11 emplace_back() is generally preferred (in terms of efficiency) to push_back() as it allows in-place construction, but is this still the case when using push_back(std::move()) with an already-constructed object?

For instance, is emplace_back() still preferred in cases like the following?

std::string mystring("hello world"); std::vector<std::string> myvector;  myvector.emplace_back(mystring); myvector.push_back(std::move(mystring)); // (of course assuming we don't care about using the value of mystring after) 

Additionally, is there any benefit in the above example to instead doing:

myvector.emplace_back(std::move(mystring)); 

or is the move here entirely redundant, or has no effect?

like image 752
Riot Avatar asked Nov 11 '14 08:11

Riot


People also ask

Is Emplace_back faster than Push_back?

With the simple benchmark here, we notice that emplace_back is 7.62% faster than push_back when we insert 1,000,000 object (MyClass) into an vector.

Should I use Push_back or Emplace_back?

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: push_back in the above case will create a temporary object and move it into the container.

Does Emplace_back copy or move?

Calling emplace_back will call the move constructor of std::string when std::move is used, which could save on a copy (so long as that string isn't stored in a SSO buffer). Note that this is essentially the same as push_back in this case.

Why do we use std :: move?

A: You should use std::move if you want to call functions that support move semantics with an argument which is not an rvalue (temporary expression).


2 Answers

Let's see what the different calls that you provided do:

  1. emplace_back(mystring): This is an in-place construction of the new element with whatever argument you provided. Since you provided an lvalue, that in-place construction in fact is a copy-construction, i.e. this is the same as calling push_back(mystring)

  2. push_back(std::move(mystring)): This calls the move-insertion, which in the case of std::string is an in-place move-construction.

  3. emplace_back(std::move(mystring)): This is again an in-place construction with the arguments you provided. Since that argument is an rvalue, it calls the move-constructor of std::string, i.e. it is an in-place move-construction like in 2.

In other words, if called with one argument of type T, be it an rvalue or lvalue, emplace_back and push_back are equivalent.

However, for any other argument(s), emplace_back wins the race, for example with a char const* in a vector<string>:

  1. emplace_back("foo") calls std::string(char const*) for in-place-construction.

  2. push_back("foo") first has to call std::string(char const*) for the implicit conversion needed to match the function's signature, and then a move-insertion like case 2. above. Therefore it is equivalent to push_back(string("foo"))

like image 71
Arne Mertz Avatar answered Oct 17 '22 09:10

Arne Mertz


The emplace_back gets a list of rvalue references and tries to construct a container element direct in place. You can call emplace_back with all types which the container element constructors supports. When call emplace_back for parameters which are not rvalue references, it 'falls back' to normal references and at least the copy constructor ist called when the parameter and the container elements are of the same type. In your case 'myvector.emplace_back(mystring)' should make a copy of the string becaus the compiler could not know that the parameter myvector is movable. So insert the std::move what gives you the desired benefit. The push_back should work as well as emplace_back for already constructed elements.

like image 42
Tunichtgut Avatar answered Oct 17 '22 09:10

Tunichtgut