C++ - Для вектора указателей на объект перераспределение вызывает удаление и копирование объектов?

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

Однако: для вектора указателей на объекты класса результат для меня менее ясен. Если я удаляю член, то, безусловно, C++ достаточно умен, чтобы просто копировать указатели вокруг - не сводя с ума удаляя указатель (и объект класса, на который он указывает), затем воссоздайте его и объект, на который он указывает снова?

Если это не так, может кто-нибудь объяснить мне этот идиотизм?

2 ответа

Решение

Вектор будет удалять, конструировать и копировать любой тип, который он содержит. В случае вектора указателей на класс / структуру, он будет удалять, конструировать и копировать указатели, оставляя фактические объекты, на которые указывают указатели, в одиночку. Это зависит от вас, чтобы распределить и освободить их.


РЕДАКТИРОВАТЬ

Пример:

Если у вас есть следующее:

class A
{
  A() {}
}

void foo(void)
{
   A * pointerToA = new A;
}

В конце области видимости функции foo освобождается только память для переменной pointerToA сам по себе, то есть 4 байта, которые содержат адрес (в 32-битном), который в этом случае хранится в стеке. Единственный способ освободить память, выделенную для нового экземпляра класса A, - это если вы вручную вызовете delete с адресом pointerToA,

Давайте возьмем пример массива класса A

A ** arrayOfPointerToA = new A*[10];
for(unsigned i = 0; i < 10; ++i)
  arrayOfPointerToA[i] = new A;

что похоже на то, что происходит, когда у вас есть std::vector<A*>, Когда вы звоните

delete [] arrayOfPointerToA;

вы освобождаете память для массива указателей, а не для каждого A,

На приведенной выше диаграмме память, выделенная в результате вышеуказанного вызова для удаления, выделена красным. Обратите внимание, что каждый A хранится в случайном месте в памяти в этом случае, так как все они были выделены отдельно.

Теперь перенесем это в вектор:

std::vector<A> эффективно использует новые A[size] выделить память. Если вы храните необработанный указатель, это будет означать, что он выделит массив типа A, что означает, что size количество объектов типа A созданы. Когда вектор освобождает свою память size количество объектов типа A уничтожены. Теперь возьмите этот пример и замените A на A*, и вы увидите, что ни один объект типа A не уничтожен.

Это фундаментальная часть работы C++ и указателей, а не просто свойство контейнеров. Если бы контейнеры произвольно вызывали delete для каждого члена, это не имело бы смысла, как если бы у нас был контейнер A мы будем вызывать delete для экземпляра объекта вместо указателя на этот объект, который недопустим.

Вектор оставит ваши значения указателя в покое. Конечно, он будет перемещать значения во внутреннем массиве при нажатии, выталкивании или удалении.

В этом случае значения являются просто указателями. Но в векторе нет логики, позволяющей определить, является ли что-то указателем на объект, и удалить / перераспределить их при копировании значений.

В случае вектора, который содержит сложный тип, а не указатель, он, конечно, попытается скопировать значения, когда внутренний массив перераспределен или перемещен.

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