Вызывается ли деструктор при удалении элемента из контейнера STL? - PullRequest
3 голосов
/ 24 июля 2010

Скажем, у меня есть два контейнера, хранящих указатели на одни и те же объекты:

std::list<Foo*> fooList;
std::vector<Foo*> fooVec;

Допустим, я удаляю объект из одного из этих контейнеров через один, если его методы:

std::vector<Foo*>::iterator itr = 
  std::find( fooVec.begin(), fooVec.end(), pToObj );
fooVec.erase( itr );

CppReference говорит, что это вызывает деструктор объекта.Означает ли это, что указатель на объект в fooList является висячим указателем?

Я бы предпочел не использовать указатели с подсчетом ссылок.Как можно решить эту проблему?

Ответы [ 5 ]

6 голосов
/ 24 июля 2010

Нет.

Когда вы удаляете указатель из контейнера, все, что вы сделали, это взяли это значение указателя из контейнера, ничего не было удалено.(то есть: у указателей нет деструктора.)

Однако опасно иметь указатели вещей в контейнерах.Подумайте:

std::vector<int*> v;
v.push_back(new int());
v.push_back(new int());
v.push_back(new int());

Если вы никогда не пройдете через контейнер и не удалите каждый из них, вы просочились.Хуже того, это не исключение.Вы должны использовать контейнер указателя , который удалит объекты, на которые он указывает, когда они будут стерты.(И все стираются, когда контейнер разрушается.)

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

1 голос
/ 24 июля 2010

Не думаю, что деструктор объекта будет вызван.Указатели в fooList должны по-прежнему указывать на действительные данные.

Если вы ссылаетесь на эту ссылку , речь идет о том, как вызовы erase сделают недействительными любые итераторы, которые вы могли быуказать на последующие места в векторе.Но аннулирование итераторов отличается от вызова delete для одной из вещей в векторе.

0 голосов
/ 24 июля 2010

В вашем случае объекты, хранящиеся в контейнерах, являются копией вашего исходного указателя, а не исходного указателя. Таким образом, для каждого Foo*, который вы решили сохранить, у вас будет 3 указателя (оригинал, один в fooList и один в fooVec), все из которых указывают на одно и то же место в памяти. Поэтому, когда вы вызываете erase, удаление будет вызываться на самом указателе, а не на том, на что он указывает, а удаление на указателях - это не операция (у них нет деструкторов, как сказал GMan).

0 голосов
/ 24 июля 2010

Оба контейнера содержат ссылки на (Foo *) объекты - поэтому, если вызывается деструктор, это деструктор объекта-указателя (который, вероятно, ничего не делает), а не самого объекта Foo.Исходный объект (класса Foo) не уничтожен, и поэтому нет висящих ссылок.

0 голосов
/ 24 июля 2010

Если у вас есть необработанный указатель на объект, деструктор не вызывается, пока вы его не удалите.

Шаблон (или это идиома?), Который вы можете использовать для гарантии того, что ваши объекты будут удалены в нужное время, а также использовать контейнеры указателей (как это требуется во многих алгоритмах), - это использовать отдельную декухранить актуальные объекты.Вы должны убедиться, что deque уничтожен после любого из контейнеров указателя.Причина, по которой вы должны использовать deque вместо вектора, заключается в том, что вы можете добавлять объекты в deque без аннулирования указателей на ранее сохраненные объекты.

...