Вызывается ли деструктор при удалении элемента из контейнера STL?

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

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 является оборванным указателем?

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


person random    schedule 24.07.2010    source источник
comment
Используйте указатели с подсчетом ссылок. Вот для чего они.   -  person Puppy    schedule 24.07.2010


Ответы (5)


No.

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

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

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

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

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

person GManNickG    schedule 24.07.2010
comment
Пожалуйста, проясните это для меня. Почему в документации по list::erase указано This effectively reduces the container size by the number of elements removed, which are destroyed. cplusplus.com/reference/list/ перечислить/удалить - person C. Tewalt; 02.09.2016
comment
@matrixugly: вам следует использовать cppreference, это намного лучше: en.cppreference.com/ w/cpp/контейнер/список/стирание. Как там поясняется, есть две перегрузки erase. Один берет ряд итераторов, и он стирает каждый элемент. - person GManNickG; 03.09.2016

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

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

person Nate Kohl    schedule 24.07.2010

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

person smichak    schedule 24.07.2010

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

person Eugen Constantin Dinca    schedule 24.07.2010

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

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

person ergosys    schedule 24.07.2010