Подтвердить что ты не робот

Что такое "удалить это"?

Сегодня я видел некоторый унаследованный код. В деструкторе есть выражение типа "delete this". Я думаю, этот вызов будет рекурсивным. Почему он работает?

Я сделал быстрый поиск по Y!, я обнаружил, что если есть необходимость ограничить пользователя созданием объекта стека, мы можем сделать destructor private и предоставить интерфейс для удаления экземпляра. В предоставленном интерфейсе мы должны вызвать delete на этом указателе.

Существуют ли другие ситуации для использования таких утверждений?

4b9b3361

Ответ 1

"удалить это" обычно используется для подсчитанных объектов. Для подсчитанного объекта решение о том, когда удалить, обычно помещается на самом объекте. Вот пример того, как будет выглядеть метод Release [1].

int MyRefCountedObject::Release() {
  _refCount--;
  if ( 0 == _refCount ) {
    delete this;
    return 0;
  }
  return _refCount;
}

Объекты ATL COM являются ярким примером этого шаблона.

[1] Да, я понимаю, что это не безопасно для потоков.

Ответ 2

delete this недействителен в деструкторе. Его можно использовать в другом месте. Но это редко бывает хорошей идеей. Структура wxWidgets использует его для своего класса потоков. Он имеет режим, когда при завершении выполнения потока он автоматически освобождает системные ресурсы и сам (объект wxThread). Мне было очень неприятно, потому что извне вы не можете знать, действительно ли это относится к ней или нет - вы больше не можете вызывать функцию типа IsValid, потому что объект не существует. Это пахнет главной проблемой с delete this, кроме проблемы, которая не может быть использована для нединамических объектов.

Если вы это сделаете, убедитесь, что вы не касаетесь какого-либо элемента данных или больше не вызываете какую-либо функцию-член на удаленном объекте. Лучше всего это делать как последнее утверждение в не виртуальной, защищенной или частной функции. Вызов delete также действителен в виртуальной и/или публичной функции, но я бы ограничил видимость метода, выполняющего это.

С++ FAQ содержит запись об этом. Стандартная цитата на С++ по моей претензии выше (3.8p5):

До того, как срок жизни объекта запустился, но после того, как хранилище, которое будет занимать объект, было выделено или, после того, как срок жизни объекта закончился и до того, как хранилище, которое объект занят, повторно используется или выпущен, любой указатель, который ссылается к месту хранения, в котором будет находиться или находится объект, может использоваться только ограниченным образом. [...] Если объект будет или имеет тип класса с нетривиальным деструктором, а указатель используется как операнд выражения-удаления, программа имеет поведение undefined.

Срок службы заканчивается, когда деструктор объекта начинает выполнение. Обратите внимание, что существуют исключения из правил, следующих за этим абзацем, для объектов, находящихся в стадии строительства и уничтожения (например, вам разрешен доступ к нестатическим элементам данных), подробно описанный в 12.7.

Ответ 3

Там, где это считается хорошим основанием для этого в ранние дни С++. Например, само удаление объекта, подсчитанного ref (как говорит JaredPar). Насколько мне известно, в конечном итоге все они оказались плохой идеей.

Ответ 4

В двусвязном списке можно удалить node без ссылки на какую-либо внешнюю структуру, такую ​​как объект "списка" высокого уровня. Это делает разумным для каждого node обрабатывать свое собственное освобождение (потенциально связанное с дополнительным статическим методом для обработки начального распределения из того же пула памяти). В этой ситуации может быть смысл для объекта node удалить себя (по запросу пользователя).

void RemoveAndDeallocate()
{
    LinkedListNode *current_prev = prev, *current_next = next;
    current_prev->next = current_next;
    current_next->prev = current_prev;
    delete this;
}

Несмотря на это, разумно, чтобы node был отсоединен от одного списка и привязан к другому списку, не освобождая память, поэтому не желательно, чтобы одна операция удаления безоговорочно освобождала память.