struct Object {
Object() { cout << "constructor\n"; }
Object(const Object &) { cout << "copy constructor\n"; }
Object(Object &&) { cout << "move constructor\n"; }
};
int main() {
vector<Object> v;
v.reserve(10);
v.emplace_back(Object{});
}
This gives me the following output:
constructor
move constructor
Why? I thought that emplace_back does create the Object in place, so that no copy or move constructors have to be called.
From the description:
The element is constructed in-place, i.e. no copy or move operations are performed.
EDIT: Ah, okay, it seems that I fundamentally misunderstood emplace_back(). You don't have to have the Object as an argument, since it is automatically created in place for you. You only have to give the arguments for the Object-constructor to emplace_back().
So, if I had a new constructor like this:
Object(int) { cout << "int constructor\n"; }
I would call emplace_back like this:
v.emplace_back(42);
instead of this:
v.emplace_back(Object(42));
Makes sense now, thanks a lot!
EDIT2: I wish I could accept all of your answers! :-P
This code demonstrates that emplace_back calls the copy constructor of A for some reason to copy the first element. But if you leave copy constructor as deleted, it will use move constructor instead.
No. It doesn't call the move constructor. To call move constructor of element you will have to call std::move while pushing to vector itself.
A move constructor enables the resources owned by an rvalue object to be moved into an lvalue without copying.
vector::emplace_back() This function is used to insert a new element into the vector container, the new element is added to the end of the vector.
emplace_back
forwards its arguments to the constructor of the vector element class, called in-place on the next available position of the vector
.
v.emplace_back(Object{});
is sort of equivalent to:
{
Object tmp;
v.emplace_back(std::move(tmp));
}
That's why you are getting a regular constructor call followed by a move constructor call.
If you want to append a new object with emplace_back
, just call:
v.emplace_back();
Just for the sake of completeness, another reason why emplace_back
might call a move constructor is: emplace_back
may cause the vector
to grow, and thus move its initial contents to their new memory location. This is not the problem here, because calling reserve
guarantees enough capacity, but generally it's an answer to the question.
v.emplace_back(Object{});
will call a placement new new (place) Object(Object{})
so a move constructor.
Use v.emplace_back();
to avoid to call extra object constructor,
which will result in new (place) Object;
emplace_back
calls whatever constructor matches the arguments you pass it. In this case you have chosen to pass Object{}
, which matches the Object&&
move constructor.
When the description says, "no move or copy is performed", it means apart from the object construction that you specify. If that construction happens to be a move or copy then of course it is performed.
If you want emplace_back
to use the no-args constructor then pass it no arguments: v.emplace_back()
.
The version you are linking is for passing constructor arguments. To achieve the desired effect, you could call v.emplace_back();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With