push_back vs emplace_back
In addition to what visitor said :
The function void emplace_back(Type&& _Val)
provided by MSCV10 is non conforming and redundant, because as you noted it is strictly equivalent to push_back(Type&& _Val)
.
But the real C++0x form of emplace_back
is really useful: void emplace_back(Args&&...)
;
Instead of taking a value_type
it takes a variadic list of arguments, so that means that you can now perfectly forward the arguments and construct directly an object into a container without a temporary at all.
That's useful because no matter how much cleverness RVO and move semantic bring to the table there is still complicated cases where a push_back is likely to make unnecessary copies (or move). For example, with the traditional insert()
function of a std::map
, you have to create a temporary, which will then be copied into a std::pair<Key, Value>
, which will then be copied into the map :
std::map<int, Complicated> m;
int anInt = 4;
double aDouble = 5.0;
std::string aString = "C++";
// cross your finger so that the optimizer is really good
m.insert(std::make_pair(4, Complicated(anInt, aDouble, aString)));
// should be easier for the optimizer
m.emplace(4, anInt, aDouble, aString);
So why didn't they implement the right version of emplace_back in MSVC? Actually, it bugged me too a while ago, so I asked the same question on the Visual C++ blog. Here is the answer from Stephan T Lavavej, the official maintainer of the Visual C++ standard library implementation at Microsoft.
Q: Are beta 2 emplace functions just some kind of placeholder right now?
A: As you may know, variadic templates
aren't implemented in VC10. We
simulate them with preprocessor
machinery for things like
make_shared<T>()
, tuple, and the new
things in<functional>
. This
preprocessor machinery is relatively
difficult to use and maintain. Also,
it significantly affects compilation
speed, as we have to repeatedly
include subheaders. Due to a
combination of our time constraints
and compilation speed concerns, we
haven't simulated variadic templates
in our emplace functions.When variadic templates are
implemented in the compiler, you can
expect that we'll take advantage of
them in the libraries, including in
our emplace functions. We take
conformance very seriously, but
unfortunately, we can't do everything
all at once.
It's an understandable decision. Everyone who tried just once to emulate variadic template with preprocessor horrible tricks knows how disgusting this stuff gets.
push_back vs emplace_back to a std::vectorstd::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.
Why would I ever use push_back instead of emplace_back?
I have thought about this question quite a bit over the past four years. I have come to the conclusion that most explanations about push_back
vs. emplace_back
miss the full picture.
Last year, I gave a presentation at C++Now on Type Deduction in C++14. I start talking about push_back
vs. emplace_back
at 13:49, but there is useful information that provides some supporting evidence prior to that.
The real primary difference has to do with implicit vs. explicit constructors. Consider the case where we have a single argument that we want to pass to push_back
or emplace_back
.
std::vector<T> v;
v.push_back(x);
v.emplace_back(x);
After your optimizing compiler gets its hands on this, there is no difference between these two statements in terms of generated code. The traditional wisdom is that push_back
will construct a temporary object, which will then get moved into v
whereas emplace_back
will forward the argument along and construct it directly in place with no copies or moves. This may be true based on the code as written in standard libraries, but it makes the mistaken assumption that the optimizing compiler's job is to generate the code you wrote. The optimizing compiler's job is actually to generate the code you would have written if you were an expert on platform-specific optimizations and did not care about maintainability, just performance.
The actual difference between these two statements is that the more powerful emplace_back
will call any type of constructor out there, whereas the more cautious push_back
will call only constructors that are implicit. Implicit constructors are supposed to be safe. If you can implicitly construct a U
from a T
, you are saying that U
can hold all of the information in T
with no loss. It is safe in pretty much any situation to pass a T
and no one will mind if you make it a U
instead. A good example of an implicit constructor is the conversion from std::uint32_t
to std::uint64_t
. A bad example of an implicit conversion is double
to std::uint8_t
.
We want to be cautious in our programming. We do not want to use powerful features because the more powerful the feature, the easier it is to accidentally do something incorrect or unexpected. If you intend to call explicit constructors, then you need the power of emplace_back
. If you want to call only implicit constructors, stick with the safety of push_back
.
An example
std::vector<std::unique_ptr<T>> v;
T a;
v.emplace_back(std::addressof(a)); // compiles
v.push_back(std::addressof(a)); // fails to compile
std::unique_ptr<T>
has an explicit constructor from T *
. Because emplace_back
can call explicit constructors, passing a non-owning pointer compiles just fine. However, when v
goes out of scope, the destructor will attempt to call delete
on that pointer, which was not allocated by new
because it is just a stack object. This leads to undefined behavior.
This is not just invented code. This was a real production bug I encountered. The code was std::vector<T *>
, but it owned the contents. As part of the migration to C++11, I correctly changed T *
to std::unique_ptr<T>
to indicate that the vector owned its memory. However, I was basing these changes off my understanding in 2012, during which I thought "emplace_back
does everything push_back
can do and more, so why would I ever use push_back
?", so I also changed the push_back
to emplace_back
.
Had I instead left the code as using the safer push_back
, I would have instantly caught this long-standing bug and it would have been viewed as a success of upgrading to C++11. Instead, I masked the bug and didn't find it until months later.
emplace_back() vs push_back() for vector
emplace_back
constructs the element in-place by forwarding the arguments to the constructor of element type, so you can
v.emplace_back(1); // forwarding 1 to Int::Int(int) to construct the element directly
push_back
always expects an element, i.e. an Int
. When you pass 1
to it as v.push_back(1);
, implicit conversion happens. A temporary Int
is constructed from 1
by (Int::Int(int)
then passed to push_back
, the element is constructed from the temporary by the move constructor of Int
later. I.e. one more move constructor invocation than v.emplace_back(1);
.
You can also pass an Int
to emplace_back
like v.emplace_back(Int(1));
, as explained above, the temporary Int
is forwarded to Int
's move constructor to construct the element, which does the same thing as v.push_back(Int(1));
.
As @JeJo suggested, there's another difference between emplace_back
and push_back
since C++17. emplace_back
returns a reference to the inserted element while push_back
returns nothing.
C++ Emplace Back vs Push Back Vector
emplace_back
passes on the arguments given to it to the constructor of the element type to construct it in-place. This is what allows emplace_back
to be used without creating a temporary object.
You are not making use of that. You are still creating a temporary in v.emplace_back(Foo(34));
with the expression Foo(34)
. A reference to this Foo(34)
temporary is then passed to the (copy) constructor of Foo
to create the element in-place, but the temporary is already created outside the emplace_back
call.
Instead, pass on just the arguments to the constructor:
v.emplace_back(34);
Which will pass 34
to the constructor of Foo
to construct it in-place without any temporary copy.
push_back is more efficient than emplace_back?
push_back
is not more efficient, and the results you observe are due to the vector resizing itself.
When you call emplace
after push_back
, the vector has to resize itself to make room for the second element. This means that it has to move the A
that was originally inside the vector, making emplace
appear more complex.
If you reserve enough space in the vector beforehand, this doesn't happen. Notice the call to va.reserve(2)
after va
's creation:
#include <iostream>
#include <vector>
class A
{
public:
A() {std::cout << "A const" << std::endl;}
~A() {std::cout << "A dest" << std::endl;}
A(const A& a) {std::cout << "A copy const" << std::endl;}
A(A&& a) {std::cout << "A move const" << std::endl;}
A& operator=(const A& a) {std::cout << "A copy operator=" << std::endl; return *this; }
A& operator=(A&& a) {std::cout << "A move operator=" << std::endl; return *this; }
};
int main () {
std::vector<A> va;
// Now there's enough room for two elements
va.reserve(2);
std::cout <<"push:" << std::endl;
va.push_back(A());
std::cout <<std::endl<< "emplace:" << std::endl;
va.emplace_back(A());
std::cout <<std::endl<< "end:" << std::endl;
return 0;
}
The corresponding output is:
push:
A const
A move const
A dest
emplace:
A const
A move const
A dest
end:
A dest
A dest
Can we make things even more efficient? Yes! emplace_back
takes whatever arguments you provide it, and forwards them to A
's constructor. Because A
has a constructor that takes no arguments, you can also use emplace_back
with no arguments! In other words, we change
va.emplace_back(A());
to
va.emplace_back(); // No arguments necessary since A is default-constructed
This results in no copy, and no move:
push:
A const
A move const
A dest
emplace:
A const
end:
A dest
A dest
A note on vectors resizing: It's important to note that the implementation of std::vector
is smart. If A
had been a trivially copyable type, std::vector
might have been able resize in-place without additional copying using a system function similar to realloc
. However because A
s constructors and destruction contain code, realloc
can't be used here.
Why emplace_back is faster than push_back?
Your test case isn't very helpful. push_back
takes a container element and copies/moves it into the container. emplace_back
takes arbitrary arguments and constructs from those a new container element. But if you pass a single argument that's already of element type to emplace_back
, you'll just use the copy/move constructor anyway.
Here's a better comparison:
Foo x; Bar y; Zip z;
v.push_back(T(x, y, z)); // make temporary, push it back
v.emplace_back(x, y, z); // no temporary, directly construct T(x, y, z) in place
The key difference, however, is that emplace_back
performs explicit conversions:
std::vector<std::unique_ptr<Foo>> v;
v.emplace_back(new Foo(1, 'x', true)); // constructor is explicit!
This example will be mildly contrived in the future, when you should say v.push_back(std::make_unique<Foo>(1, 'x', true))
. However, other constructions are very nice with emplace
, too:
std::vector<std::thread> threads;
threads.emplace_back(do_work, 10, "foo"); // call do_work(10, "foo")
threads.emplace_back(&Foo::g, x, 20, false); // call x.g(20, false)
Using make_shared with emplace_back and push_back - any difference?
vector<T>::push_back
has a T&&
overload, which does the same as the vector<T>::emplace_back
T&&
version.
The difference is that emplace_back
will perfect-forward any set of arguments to the T
's constructor, while push_back
only takes T&&
or T const&
. When you actually pass a T&&
or T const&
the standard specification of their behaviour is the same.
emplace_back() vs push_back when inserting a pair into std::vector
emplace_back
takes a variadic parameter pack as argument:
template< class... Args >
reference emplace_back( Args&&... args );
When you call it like this: emplace_back({1, 2})
you are calling it with one argument i.e. {1, 2}
and the Args
cannot be deduced. That is because of how the language has evolved. In C++ {1, 2}
doesn't have a type. It is a brace enclosed init-list and can be used in certain types of initializations, but all require the type of the initialized to be known. That is why temp_pair = {1,2};
works, because the type of temp_pair
is know and has a constructor matching (int, int)
.
Anyway emplace_back
wasn't supposed to be used like that, but like this instead:
my_vec.emplace_back(1, 2);
Also please note that even if these work:
my_vec.emplace_back(std::pair<int, int>{1, 2});
my_vec.emplace_back(temp_pair);
They shouldn't be used. They add no advantage over push_back. The whole point of emplace_back
is to avoid creating a temporary T
. The above calls all create the temporary std::pair<int, int>
.
but I thought you can use
emplace_back()
anywhere that you have
push_back()
For the most part that's correct. At least that was the intention. And you can indeed use it in your cese. You just have to adjust the syntax a little. So instead of push_back({1, 2})
you can use emplace_back(1, 2)
.
There is a situation where unfortunately you can't use emplace_back
: aggregates.
struct Agg
{
int a, b;
};
auto test()
{
Agg a{1, 2}; // ok, aggregate initialization
std::vector<Agg> v;
v.emplace_back(1, 2); // doesn't work :(
}
This doesn't work unless you add a constructor for Agg
. This is considered an open defect in the standard, but unfortunately they can't find a good solution to this. The problem is with how brace init initialization works and if you use it in generic code you can miss some constructors. For all the nitty-gritty details check this great post: Why can an aggreggate struct be brace-initialized, but not emplaced using the same list of arguments as in the brace initialization?
Efficiency of C++11 push_back() with std::move versus emplace_back() for already constructed objects
Let's see what the different calls that you provided do:
emplace_back(mystring)
: This is an in-place construction of the new element with whatever argument you provided. Since you provided an lvalue, that in-place construction in fact is a copy-construction, i.e. this is the same as callingpush_back(mystring)
push_back(std::move(mystring))
: This calls the move-insertion, which in the case ofstd::string
is an in-place move-construction.emplace_back(std::move(mystring))
: This is again an in-place construction with the arguments you provided. Since that argument is an rvalue, it calls the move-constructor ofstd::string
, i.e. it is an in-place move-construction like in 2.
In other words, if called with one argument of type T, be it an rvalue or lvalue, emplace_back
and push_back
are equivalent.
However, for any other argument(s), emplace_back
wins the race, for example with a char const*
in a vector<string>
:
emplace_back("foo")
callsstd::string(char const*)
for in-place-construction.push_back("foo")
first has to callstd::string(char const*)
for the implicit conversion needed to match the function's signature, and then a move-insertion like case 2. above. Therefore it is equivalent topush_back(string("foo"))
Related Topics
The Static Keyword and Its Various Uses in C++
Why Is Unsigned Integer Overflow Defined Behavior But Signed Integer Overflow Isn'T
What Xml Parser Should I Use in C++
"Using Namespace" in C++ Headers
Why Do I Need Strand Per Connection When Using Boost::Asio
Why Are C Character Literals Ints Instead of Chars
What Are Some Uses of Template Template Parameters
How to Print a List of Elements Separated by Commas
Opencv C++/Obj-C: Detecting a Sheet of Paper/Square Detection
Why Are Preprocessor Macros Evil and What Are the Alternatives
Raii and Smart Pointers in C++
Given an Integer N. What Is the Smallest Integer Greater Than N That Only Has 0 or 1 as Its Digits