According to cppreference, std::vector::emplace_back
has only one signature, which is:
template< class... Args >
reference emplace_back( Args&&... args );
And in the description, it says emplace_back
is supposed to forward each of its arguments to the constructor of the type in the vector
. However, when I tested the following code using gcc 12.2, it successfully compiles:
#include <iostream>
#include <vector>
class Foo
{
public:
int x;
int y;
Foo(int x, int y) : x(x), y(y)
{}
};
int main()
{
std::vector<Foo> foos;
Foo foo(1, 2);
foos.push_back(std::move(foo));
foos.emplace_back(foo); // weird
}
(See on compiler explorer)
I expected the line foos.emplace_back(foo);
to fail the compilation. It seems as if emplace_back
has this overload:
template< class T >
reference emplace_back( T& arg );
which isn't mentioned in the documentation. Am I missing something or is this just a compiler extension?
CodePudding user response:
foos.emplace_back(foo); // weird
That's weird indeed! You ask to emplace_back
, meaning you're calling the constructor, and you're passing foo
to the constructor. Hence, you're calling the copy constructor. push_back
would have done the same!
That's an implicitly defined default copy constructor, see cppreference on Copy Constructors:
If no user-defined copy constructors are provided for a class type (struct, class, or union), the compiler will always declare a copy constructor as a non-explicit inline public member of its class.
You didn't define a copy constructor, so the compiler did that for you, as dictated by C . You can avoid that and make your compilation fail:
class Foo
{
public:
int x;
int y;
Foo(int x, int y) : x(x), y(y)
{}
//! Explicitly deleted default copy constructor.
Foo(const Foo&) = delete;
};
foos.push_back(std::move(foo));
He're you're calling the move constructor. Note that you're using foo
after moving from it, that's more or less illegal (you throwing std::move
at foo
means that foo
is no longer supposed to hold any resources.)
Should you really happen to just want to delete the move constructor, same syntax, basically: Foo(Foo&&) = delete;
.
CodePudding user response:
template< class... Args >
reference emplace_back( Args&&... args );
can deduced to something like (with Args = Foo&
)
reference emplace_back( Foo& && args[0] );
which collapse to
reference emplace_back( Foo& args[0] );