46

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?

Community
  • 1
  • 1
Channel72
  • 24,139
  • 32
  • 108
  • 180
  • 1
    this looks similar: http://stackoverflow.com/questions/4303513/push-back-vs-emplace-back – moka Aug 09 '11 at 18:03
  • 7
    Good question. @moka he knows the difference between what the two functions do. He even linked to that particular question. –  Aug 09 '11 at 18:06
  • 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 v;` with implicit conversion from `int`. – Gene Bushuyev Aug 09 '11 at 18:09
  • 1
    @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 Aug 09 '11 at 18:37
  • 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 Aug 09 '11 at 19:04
  • @Benjamin -- it's obvious, in one case you move the temporary, in the other you construct an object in place. It's a trivial example for illustration purposes, but it does show the difference. – Gene Bushuyev Aug 09 '11 at 20:06

2 Answers2

41

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.

Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
  • 7
    It is especially useful when handling containers of `unique_ptr`s, since `v.emplace_back(new foo)` is much simpler than `v.push_back(std::unique_ptr(new foo))`. But one should be able to *request explicitly* the conversion in this case. – Alexandre C. Jul 16 '12 at 18:53
  • @AlexandreC.: Actually, `emplace_back(new foo)` is not exception-safe, so it's the wrong thing to do. – user541686 Jun 25 '17 at 01:58
  • @AlexandreC.: Yeah -- specifically the potential allocation required to enlarge the vector. A potential meta-lesson to take away here is: don't use a new feature out of pure laziness in typing when using it is not actually necessary. – user541686 Jun 25 '17 at 07:36
  • @AlexandreC.: Can't tell if you're joking, but you should just use `push_back(make_unique())` if you're not sticking with the original (which would be fine by me too)... – user541686 Jun 25 '17 at 07:38
  • @Mehrdad C++ has become a tad verbose lately, hasn't it. Yes, the template was a joke. I fully agree with you, but at the time I wrote that comment, we were using Visual Studio 2010, with no support of `make_unique`, and we still occasionally compile code with it. Nowadays, we grep for `new` and `delete` in our codebase. – Alexandre C. Jun 25 '17 at 08:06
  • ...and emulate `make_unique` with a dozen templates, all put (disgustingly) under `namespace std` ;) – Alexandre C. Jun 25 '17 at 08:07
0

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 &)
}
user541686
  • 205,094
  • 128
  • 528
  • 886