Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does std::vector::emplace call destructor without any copy constructor called?

I am storing objects inside a std::vector, and I want to avoid calling destructor as much as possible.
I replaced copy constructor and assignments by move ones:

class Object
{
    Object(const Object&) = delete;
    Object(Object&&);
    Object& operator=(const Object&) = delete;
    Object& operator=(Object&&);
    [...]
};

I am initializing it like this:

std::vector<Object>   container;

container.reserve(42) // Reserve a lot in order to be sure it won't be a problem

Then, I add two elements with emplace_back (the constructor takes one int parameter):

container.emplace_back(1);
container.emplace_back(3);

Until there, everything is fine. But then I want to insert an element before the last one with emplace:

auto it = container.end();

it--; // Last position.
it--; // Before last position.
container.emplace(it, 2);

But here a destructor is called.

I tried to locate why with Valgrind, it appears emplace function calls _M_insert_aux that call my destructor.

How could I avoid that?

like image 958
Aracthor Avatar asked Apr 21 '26 09:04

Aracthor


1 Answers

You can't avoid that. This is simply how a vector works. It's a contiguous array. The only way you can insert a new element into a contiguous array is to move the old elements down. That means using move assignment to move them into their new positions.

So if you have the following vector, and their contents:

[5][12][16]

If you insert after the second element, then at some point you have this:

[5][12][*][16]

Where "*" is the value of a moved-from element.

Then comes the emplace. emplace explicitly will construct the value in place; that's what its for. However, there is already a live object in the 3rd element: the moved-from value.

Therefore, this object must be destroyed before the new object can be constructed in its place. Hence the destructor must be called.

If you used insert rather than emplace, then you would still have a destructor be called. But that would be the destructor of the object you pass to the insert function.

So there's going to be an "extra" destructor called somewhere.

But really, you shouldn't be worried about the number of destructor calls. Focus on absolute costs. Generally speaking, if you have a move-only type, the destructor for a moved-from value will be cheap.

like image 74
Nicol Bolas Avatar answered Apr 22 '26 21:04

Nicol Bolas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!