Какая польза от "удалить это"?
Сегодня я видел какой-то устаревший код. В деструкторе есть утверждение типа "delete this
". Думаю, этот вызов будет рекурсивным. Почему он работает?
Я сделал быстрый поиск по Y!, и обнаружил, что если есть необходимость ограничить пользователя в создании стекового объекта, мы можем сделать деструктор приватным и предоставить интерфейс для удаления экземпляра. В предоставленном интерфейсе мы должны вызвать delete для этого указателя.
Есть ли другие ситуации для использования таких утверждений?
4 ответа
"Удалить это" обычно используется для объектов с подсчетом ссылок. Для объекта с подсчетом ссылок решение о том, когда удалять, обычно размещается на самом объекте. Вот пример того, как будет выглядеть метод Release [1].
int MyRefCountedObject::Release() {
_refCount--;
if ( 0 == _refCount ) {
delete this;
return 0;
}
return _refCount;
}
COM-объекты ATL являются ярким примером этого шаблона.
[1] Да, я понимаю, что это не безопасно.
delete this
недопустимо в деструкторе. Это может быть использовано в другом месте. Но это очень редко хорошая идея. wxWidgets
Framework использует его для своего класса потока. У него есть режим, в котором, когда поток завершает выполнение, он автоматически освобождает системные ресурсы и себя (объект wxThread). Я нахожу это очень раздражающим, потому что со стороны вы не можете знать, является ли действительным ссылаться на него или нет - вы не можете вызвать такую функцию, как IsValid
больше, потому что объект не существует. Это пахнет как главная проблема с delete this
кроме проблемы, что он не может быть использован для не динамических объектов.
Если вы сделаете это, убедитесь, что вы не трогаете какой-либо элемент данных или больше не вызываете какую-либо функцию-член для объекта, который вы удалили таким образом. Лучше всего делать это как последнее утверждение в не виртуальной, защищенной или закрытой функции. Вызов delete действителен и в виртуальной и / или публичной функции, но я бы ограничил видимость метода, который делает это.
В C++ FAQ есть запись об этом. C++ Стандартная цитата по моей претензии выше (3.8p5
):
До того, как началось время жизни объекта, но после того, как было выделено хранилище, которое будет занимать объект, или, после того, как закончился срок жизни объекта, и до того, как хранилище, которое занимал объект, будет повторно использовано или освобождено, любой указатель, который ссылается на хранилище Место, где будет или будет находиться объект, может использоваться, но только ограниченным образом. [...] Если объект будет или имел тип класса с нетривиальным деструктором, и указатель используется как операнд выражения удаления, программа имеет неопределенное поведение.
Время жизни заканчивается, когда деструктор объекта начинает выполнение. Обратите внимание, что существуют исключения из правил, следующих за этим абзацем для объектов, находящихся в процессе строительства и уничтожения (например, вам разрешен доступ к нестатическим элементам данных), подробно 12.7
,
Там, где считаются вескими причинами сделать это в первые дни C++. Например, самостоятельное удаление объекта с подсчетом ссылок (как говорит JaredPar). Насколько я знаю, все они были признаны плохой идеей в долгосрочной перспективе.
В двусвязном списке можно удалить узел, не ссылаясь на какую-либо внешнюю структуру, такую как высокоуровневый объект "список". Это делает разумным, чтобы каждый узел обрабатывал свое собственное освобождение (потенциально в сочетании с дополнительным статическим методом для обработки начального выделения из того же пула памяти). В этой ситуации может иметь смысл удалить объект узла (по запросу пользователя).
void RemoveAndDeallocate()
{
LinkedListNode *current_prev = prev, *current_next = next;
current_prev->next = current_next;
current_next->prev = current_prev;
delete this;
}
Хотя также разумно, чтобы узел был отсоединен от одного списка и связан с другим списком без освобождения памяти, поэтому нежелательно, чтобы одна операция удаления безоговорочно освобождала память.