39

Trying to understand the difference between using push() or emplace() for std::stack.

I was thinking that if I create a std::stack<int>, then I'd use push() because integer is a primitive type and there is nothing for emplace() to construct.

However, if I was creating std::stack<string> then I'd choose emplace() because std::string is an object.

Is this correct usage?

Piper
  • 1,266
  • 3
  • 15
  • 26
Joshua Oliphant
  • 902
  • 3
  • 10
  • 17
  • 1
    I had read that push_back vs emplace_back, or tried to at least, but I'm wondering if someone has a simpler answer for someone like me who is a bit new to c++. – Joshua Oliphant Oct 05 '14 at 00:32
  • 6
    Not a duplicate. What that one is actually asking about is a MSVC10 bug. Although this question might already have been asked, somewhere else, it wasn't asked there. – Sam Varshavchik Oct 05 '14 at 00:49
  • 1
    Why is everyone talking about this emplace_back() thing? I am interested in the C++11 emplace() method and the point of that over using push(). http://www.cplusplus.com/reference/stack/stack/emplace/ – Will May 06 '17 at 08:44

2 Answers2

83

To fully understand what emplace_back does, one must first understand variadic templates and rvalue references.

This is a fairly advanced, and deep concept in modern C++. On a map, it would be labeled "there be dragons".

You say that you're new to C++ and trying to learn this stuff. This may not be the answer you might be looking for, but you should skip this detail for now, and come back later after you've wrapped your brain around variadic templates and rvalue references. Then it should all make sense.

But if you insist: for a container containing simple, elementary types like integers, there's little, if any difference. The difference comes when the container's type is some large, sophisticated class, with a complicated constructor, and/or copy-constructor.

The end result of either push or emplace is exactly, 100%, the same. The container gets another element appended to it. The difference is where the element comes from:

1) push takes an existing element, and appends a copy of it to the container. Simple, straightforward. push always takes exactly one argument, the element to copy to the container.

2) emplace creates another instance of the class in the container, that's already appended to the container. The arguments to emplace are forwarded as arguments to the container's class's constructor. Emplace can have either one argument, more than one argument, or no argument at all, if the class has a default constructor.

Note that when the class's constructor takes one argument and it is not marked as explicit, it's possible to abuse push and pass it a constructor argument, instead of an existing instance of the class. But let's pretend that this option does not exist, it often leads to horrible code performance, especially with non-trivial classes.

So: if you want to add a copy of an existing instance of the class to the container, use push. If you want to create a new instance of the class, from scratch, use emplace.

JFMR
  • 23,265
  • 4
  • 52
  • 76
Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • 2
    I think I'm understanding when I would use emplacement I stead of push. I will certainly be looking up information on variadic templates and rvalue references. – Joshua Oliphant Oct 05 '14 at 01:11
  • 1
    Would there be any downside to just always flat-out using `emplace`, even if the object I want to add already exists? – antred Jul 29 '17 at 18:16
  • 2
    @antred - push_back() allows uniform initialization syntax. emplace_back(), given that it's a template function, does not. – Sam Varshavchik Jul 30 '17 at 00:15
21

If you have a vector<X>, then emplace_back(a, b, c)constructs the X object inside the vector.

By contrast, push_back(X(a, b, c)) first creates a temporary, which is then moved into the vector.

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • 3
    then, what about `emplace_back(X(a,b,c))`? – avocado Oct 22 '16 at 11:30
  • 4
    This will create the temporary X(a,b,c), and attempt to construct X inside the vector taking the temporary as an argument, which should use the move constructor. In general, if you want to know what will happen with emplace, ask yourself 'what would happen if I replace emplace_back with the object name'? It's basically doing exactly that -- except the memory it's using is exactly where the vector wants it to be so the additional move/copy step push_back needs to do is avoided. – Chuu Jun 28 '19 at 22:22