Просто чтобы объяснить, как именно UD может вас укусить ...
Если вы erase()
элемент - явно вызываете деструктор - этот деструктор может делать такие вещи, как уменьшение счетчиков ссылок + очистка, удаление указателей и т. Д. Когда ваш деструктор массива <> затем делает delete[] element
, это вызовет деструкторы для каждого элемента по очереди, и для стертых элементов эти деструкторы могут повторить обслуживание счетчика ссылок, удаление указателя и т. д., но на этот раз исходное состояние не соответствует ожидаемому, и их действия могут привести к сбою программы.
По этой причине, как говорит Бен в своем комментарии к ответу Джеймса, вы, безусловно, должны были заменить стертый элемент - используя размещение нового - до вызова деструктора массива, поэтому деструктор будет иметь какое-то законное состояние, из которого он будет разрушен. .
Простейший тип T
, иллюстрирующий эту проблему:
struct T
{
T() : p_(new int) { }
~T() { delete p_; }
int* p_;
};
Здесь значение p_
, установленное new
, будет удалено во время erase()
, и если оно не изменится при запуске ~array()
. Чтобы исправить это, p_
должен быть изменен на что-то, для чего delete
действителен до ~array()
- либо каким-либо образом очистив его до 0, либо до другого указателя, возвращенного new
. Наиболее разумным способом сделать это является размещение new
, которое создаст новый объект, получив новое и действительное значение для p_
, перезаписав старое и бесполезное содержимое памяти.
Тем не менее, вы можете подумать, что можете создавать типы, для которых повторный деструктор безопасен: например, установив p_
в 0 после delete
. Это, вероятно, будет работать на большинстве систем, но я уверен, что в Стандарте есть что-то, что дважды вызывает деструктор - это UD независимо от того,