Из моего понимания до сих пор, если у вас есть вектор объектов класса, если вы удаляете какой-либо элемент вектора, обычно вектор перераспределяет некоторые из своих объектов для сохранения смежности памяти. Следовательно, вам нужно реализовать правило трех (деструктор, конструктор копирования и оператор копирования) для всего, что будет сохранено при удалении векторных элементов.
Однако: для вектора указателей на объекты класса результат для меня менее ясен.
Если я удаляю член, то, несомненно, C ++ достаточно умен, чтобы просто копировать указатели вокруг — не сводя с ума удаляя указатель (и объект класса, на который он указывает), затем заново создайте его и объект, на который он указывает снова?
Если это не так, может кто-нибудь объяснить мне этот идиотизм?
Вектор будет удалять, конструировать и копировать любой тип, который он содержит. В случае вектора указателей на класс / структуру он будет удалять, создавать и копировать указатели, оставляя фактические объекты, на которые указывают указатели, в одиночку. Это зависит от вас, чтобы распределить и освободить их.
Пример:
Если у вас есть следующее:
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 для экземпляра объекта вместо указателя на этот объект, который недопустим.
Вектор оставит ваши значения указателя в покое. Конечно, он будет перемещать значения во внутреннем массиве при нажатии, выталкивании или удалении.
В этом случае значения являются просто указателями. Но в векторе нет логики, позволяющей определить, является ли что-то указателем на объект, и удалить / перераспределить их при копировании значений.
В случае вектора, который включает в себя сложный тип, а не указатель, он, конечно, попытается скопировать значения, когда внутренний массив перераспределен или перемещен.