Aracthor
Aracthor

Reputation: 5917

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?

Upvotes: 3

Views: 2121

Answers (1)

Nicol Bolas
Nicol Bolas

Reputation: 474036

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.

Upvotes: 2

Related Questions