45
votes

Firstly, I'm aware of this question, but I don't believe I'm asking the same thing.

I know what std::vector<T>::emplace_back does - and I understand why I would use it over push_back(). It uses variadic templates allowing me to forward multiple arguments to the constructor of a new element.

But what I don't understand is why the C++ standard committee decided there was a need for a new member function. Why couldn't they simply extend the functionality of push_back(). As far as I can see, push_back could be overloaded in C++11 to be:

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

This would not break backwards compatibility, while allowing you to pass N arguments, including arguments that would invoke a normal rvalue or copy constructor. In fact, the GCC C++11 implementation of push_back() simply calls emplace_back anyway:

  void push_back(value_type&& __x)
  { 
    emplace_back(std::move(__x)); 
  }

So, the way I see it, there is no need for emplace_back(). All they needed to add was an overload for push_back() which accepts variadic arguments, and forwards the arguments to the element constructor.

Am I wrong here? Is there some reason that an entirely new function was needed here?

2
Good question. @moka he knows the difference between what the two functions do. He even linked to that particular question.user802003
They have different meanings, it's all explained in the question you mentioned you read. Compare v.emplace_back(123) and v.push_back(123) for example for vector<SomeType> v; with implicit conversion from int.Gene Bushuyev
@Gene: Okay, I've compared them, and I don't see what the difference would be if push_back was simply modified to do what emplace_back does. Would you mind expounding upon it here?Benjamin Lindley
That's pretty standard practice for library development. You don't change your interface you make a new one. Then allow users to implement the old API in terms of the new API at their own pace while the code never becomes broken.AJG85

2 Answers

42
votes

If T has an explicit conversion constructor, there is different behavior between emplace_back and push_back.

struct X
{
    int val;
    X() :val() {}
    explicit X(int v) :val(v) {}
};

int main()
{
    std::vector<X> v;
    v.push_back(123);    // this fails
    v.emplace_back(123); // this is okay
}

Making the change you suggest would mean that push_back would be legal in that instance, and I suppose that was not desired behavior. I don't know if this is the reason, but it's the only thing I can come up with.

0
votes

Here's another example.

Honestly, the two are semantically so different, that their similar behavior should be regarded as a mere coincidence (due to the fact that C++ has "copy constructors" with a particular syntax).

You should really not use emplace_back unless you want in-place-construction semantics.
It's rare that you'd need such a thing. Generally push_back is what you really, semantically want.

#include <vector>

struct X { X(struct Y const &); };
struct Y { Y(int const &); operator X(); };

int main()
{
    std::vector<X> v;
    v.   push_back(Y(123));  // Calls Y::operator X() and Y::Y(int const &)
    v.emplace_back(Y(123));  // Calls X::X(Y const &) and Y::Y(int const &)
}