Почему std::vector::emplace вызывает деструктор без вызова конструктора копирования?

Я храню предметы внутри std::vectorи я хочу, чтобы как можно больше не вызывать деструктор.
Я заменил конструктор копирования и назначения на перемещения:

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

Я инициализирую это так:

std::vector<Object>   container;

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

Затем я добавляю два элемента с помощью emplace_back (конструктор занимает один int параметр):

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

Пока там все нормально. Но затем я хочу вставить элемент перед последним с помощью emplace:

auto it = container.end();

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

Но здесь деструктор называется.

Я пытался найти, почему с Valgrind, кажется, emplace вызовы функций _M_insert_aux это называется мой деструктор.

Как я мог избежать этого?

1 ответ

Решение

Вы не можете избежать этого. Это просто как vector работает. Это непрерывный массив. Единственный способ вставить новый элемент в непрерывный массив - это переместить старые элементы вниз. Это означает, что вы используете перемещение, чтобы переместить их на новые позиции.

Так что если у вас есть следующий вектор и их содержимое:

[5][12][16]

Если вы вставите после второго элемента, то в какой-то момент у вас есть это:

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

Где "*" - это значение элемента, из которого был сделан переход.

Затем наступает emplace, emplace явно создаст значение на месте; вот для чего это. Тем не менее, в третьем элементе уже есть живой объект: значение "от".

Следовательно, этот объект должен быть уничтожен до того, как новый объект будет построен на его месте. Следовательно, деструктор должен быть вызван.

Если вы использовали insert скорее, чем emplace тогда у тебя все равно будет деструктор. Но это будет деструктор объекта, который вы передаете insert функция.

Так что где-то будет "лишний" деструктор.

Но на самом деле, вы не должны беспокоиться о количестве вызовов деструкторов. Фокус на абсолютных затратах. Вообще говоря, если у вас есть тип "только для перемещения", деструктор для значения "перемещенный из" будет дешевым.

Другие вопросы по тегам