7

A similar questions exist in here and here but I think we haven't got a clear answer then I remake the question.

The C++11 standards has two ways to add a new element in the end of vector they are std::vector::push_back and std::vector::emplace_back.

The difference between them is the std::vector::emplace_back construct the object in place and std::vector::push_back basically copy the object (or primitive type) or move it to the end of vector.

Then std::vector::push_back looks the better option to add primitive types into a std::vector. For example:

std::vector<int> vVec;
vVec.push_back(10);
int iVar 30;
vVec.push_back(iVar);

But it is not so clear to me when we talk about objects. Let's take a vector of std::string for example. If I want to add a literal string I shall use std::vector::emplace_back and when I want to copy or move a string object I shall use std::vector::push_back?

To make more clear what I'm asking about, let's see a few scenarios:

1st scenario:

std::vector<string> vVec;
std::string sTest("1st scenario");
vVec.push_back(sTest);  
vVec.emplace_back(sTest); 

Push_back make a copy of sTest and associate to the new element in the end of vVec meanwhile emplace_back create the string object in the end of vVec and copy the content of sTest into it. Which one is more efficient in this case or doesn't matter?

2nd scenario:

std::vector<string> vVec;
std::string sTest1("2st scenario");
std::string sTest2("2st scenario");
vVec.push_back(move(sTest1));   
vVec.emplace_back(move(sTest2)); 

Push_back is ready to move semantic, but what happens with emplace_back? Which one is more efficient in this case?

3rd scenario:

std::vector<string> vVec;
std::string sTest("3st scenario");
vVec.push_back(sTest.substr(4,4));
vVec.emplace_back(sTest.substr(4,4));

Because the std::string::substr returns another std::string we have the same situation as the 2nd scenario?

Conclusion

if std::vector::emplace_back is more efficient than std::vector::push_back only when literals is involved (in place construction), does it really justifiable to be used? If does, can you give me some examples?

Important to note that std::vector::emplace_back was implemented in c++11 not in c++0x then I suppose it has a good reason to exists.

Enlico
  • 23,259
  • 6
  • 48
  • 102
TheArchitect
  • 1,160
  • 4
  • 15
  • 26
  • 2
    why would you first construct a string and them move it to `emplace_back`? sorry, but I find your examples confusion rather than clarifying. Afaik `emplace_back` saves you from constructing the instance before pushing it, so your comparisons arent really fair imho – 463035818_is_not_an_ai Apr 24 '17 at 19:48
  • Emplace_back doesn't save me to construct the instance it does in place, in other words a customized constructor. In fact, I want to know if emplace_back acts exactly as push_back and it has or hasn't some advantage over push_back. – TheArchitect Apr 24 '17 at 20:14
  • _"basically copy the object (or primitive type)"_ Primitive types are objects too. Any type you can store in a std::vector is an object type. – Jonathan Wakely Apr 24 '17 at 20:18
  • of course you have to construct an instance at some point, but with `emplace_back` you do not need to construct an instance outside of the container, before you push it. In most of your examples you do create an instance before you insert it into the vector, hence it is pointless imho to compare `push_back` and `emplace_back` for those cases – 463035818_is_not_an_ai Apr 25 '17 at 06:49

3 Answers3

13

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.)

aschepler
  • 70,891
  • 9
  • 107
  • 161
  • `vector` is fine if you delete move and copy constructors, you just won't be able to call `push_back`. – Nir Friedman Apr 24 '17 at 20:33
  • You could also mention that for types with move-operations that are not marked `nothrow` `push_back` will copy instead of move existing elements into a new buffer if it needs to be resized. So unless one really cares about the strong exception guarantee, `emplace_back` should always be preferred. – Corristo Apr 24 '17 at 22:30
13

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&&)
Passer By
  • 19,325
  • 6
  • 49
  • 96
2

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:

  1. A vector of MyObject
  2. MyObject needs to receive 3 arguments to be constructed
  3. 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.

TheArchitect
  • 1,160
  • 4
  • 15
  • 26