push_back vs emplace_back to a std::vector<std::string>
It doesn't make much of a difference in your three scenarios, since both functions will call one copy constructor in scenario 1 and one move constructor in scenario 2 or 3.
But what if you want to construct a string of 10 'x'
characters? In this case, your choices are
vVec.push_back(std::string(10, 'x'));
vVec.emplace_back(10, 'x');
In this case, push_back
involves calling a custom string
constructor and then a move constructor, but emplace_back
calls the custom string
constructor directly, saving the call to the move constructor.
A move constructor for std::string
may not be a huge deal, but emplace
functions can save when objects don't have an efficient move constructor, and can be used even if the class type has a deleted move constructor for some reason. (Okay, std::vector
won't be happy if you delete the move and copy constructors, but other containers would be okay with it.)
First lets clarify:
The emplace
family accepts arguments for constructors, not the object itself.
Then it constructs the object in place with those arguments, it will never construct a temporary object then copy or move it into the container.
That said, taking an object of the same type as an argument is exactly what copy and move constructing is doing, which is why in your examples, they call the same constructors: they are called with a already constructed string
.
Where emplace
and push
is completely different is where emplace
is called with constructor arguments that is not the object itself: emplace
does not need to construct a temporary then copy into the container.
std::vector<std::string> strvec;
strvec.emplace_back("abc") //calls string(const char*)
strvec.push_back("abc") //is equivalent to...
strvec.push_back(string("abc")) //which calls string(const char*) then string(string&&)
I take a while to really understand what the advantage to use std::vector::emplace as aschepler said.
I found out the better scenario to use that is when we have our own class that receive some data when it is construct.
To make more clear, let's suppose we have:
- A vector of MyObject
- MyObject needs to receive 3 arguments to be constructed
- The functions get1stElem(), get2ndElem() and get3rdElem() provide the elements necessary to construct a MyObject instance
Then we can have a line like this:
vVec.emplace(get1stElem(), get2ndElem(), get3rdElem());
Then the std::vector::emplace will construct MyObject in place more efficiently than std::vector::push_back.