, что произойдет, если вы выполните «delete this?» в функции-члене?

17

Что произойдет, если функция-член попытается выполнить delete this; , как в конструкторе следующего класса?

class A
{
public:
    A(int);
    ~A();
    int *pi;
}

A::A(int i)
{
    delete this;
    pi = new int(i);
}

A::~A()
{
    delete pi;
}
    
задан zhanwu 12.08.2011 в 13:43
источник
  • Использование delete this; Это хорошо. Выполнение этого в конструкторе, а также доступ к полям объектов после него - неопределенное поведение. К сожалению, это, как правило, не вызывает ошибки процессора, просто куча коррупции. –  Hans Passant 12.08.2011 в 13:52
  • Ответ Als объясняет условия, которые очень хорошо подходят для этого, и этими условиями ваш код не в порядке. Внутри конструктора вам разрешено исключать исключение. –  Sebastian 12.08.2011 в 14:05

5 ответов

35

Этот C ++ FAQ отвечает на это довольно красиво, повторяя здесь:

Пока вы будете осторожны, это нормально для объекта delete this .

Вот как я определяю «осторожно»:

  • Вы должны быть абсолютно уверены в том, что этот объект был выделен через новый (а не новый [], ни место размещения new, ни локальный объект в стеке, ни глобальный, ни член другого объекта; простым обычным новым).
  • Вы должны быть абсолютно уверены, что ваша функция-член будет последней функцией-членом, вызываемой на этом объекте.
  • Вы должны быть абсолютно на 100% уверенно уверены, что остальная часть вашей функции-члена (после удаления этой строки) не касается какой-либо части этого объекта (включая вызов любых других функций-членов или касание любых элементов данных) .
  • Вы должны быть абсолютно на 100% уверенно уверены, что никто даже не коснется этого указателя после удаления этой строки. Другими словами, вы не должны его проверять, сравнивать с другим указателем, сравнивать его с NULL, печатать его, бросать, делать с ним что-либо.

Вы нарушаете # 3 , обратившись к pi после delete this

    
ответ дан Alok Save 12.08.2011 в 13:57
источник
  • Я думаю, вы должны указать, что данный пример не удовлетворяет требованию 3, потому что член pi открывается после удаления этого в конструкторе. –  Sebastian 12.08.2011 в 14:03
  • @Sebastian: Done, Спасибо, что указали это. Лучше прямо указать это. –  Alok Save 12.08.2011 в 14:08
  • Это может быть законным, но это очень strong показатель того, что у вас неправильный дизайн. Управление ресурсами и бизнес-логикой не следует переплетать. Объект, который управляет собой, не является правильно сконструированным объектом, поскольку он не может знать о большем контексте. Всегда лучше делегировать уничтожение менеджеру. Вместо того, чтобы разрушать себя, было бы лучше зарегистрировать себя для уничтожения с помощью объекта-менеджера, который лучше понимает контекст. –  Martin York 12.08.2011 в 16:13
  • @Martin: Я не согласен. Этот трюк используется в COM (косвенно, с помощью Release ()), чтобы убедиться, что для удаления используется тот же самый распределитель памяти, который используется для выделения объекта. Это должно обязательно вызвать какой-то сигнал, когда вы вводите его, но есть по крайней мере 1 веская причина использовать эту конструкцию. –  André Caron 23.08.2011 в 21:50
  • @ Андре Каро: COM - прекрасный пример того, почему это плохой дизайн. COM почти равномерно считается ошибкой (возможно, это была хорошая идея в то время, но C ++ так сильно развился, что с тех пор это считается плохим). –  Martin York 24.08.2011 в 08:15
Показать остальные комментарии
3

Плохие вещи. Вы можете delete this; , но это, как правило, очень плохая идея, и как только это будет сделано, вы не сможете коснуться каких-либо переменных-членов или функций-членов.

    
ответ дан Puppy 12.08.2011 в 13:44
источник
1

В общем случае вызов delete this изнутри функции-члена определен корректно, если немного рискованно.

Но это, вероятно, очень плохая идея, чтобы вызвать его из конструктора (я не знаю, хорошо ли он определен). Зачем вам это делать?

    
ответ дан Oliver Charlesworth 12.08.2011 в 13:44
источник
0

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

В вашем примере почти то же самое произойдет, если вы сделали

class A
{
public:
    A(int);
    int *pi;
};

A::A(int i)
{
    pi = new int(i);
}

int main()
{
   A* p = new A(10);
   delete p;
   p->pi = new int; //bad stuff

//or
   A a(20);
   delete &a;  //bad stuff
   a.pi = new int; //more bad stuff
}

И даже более плохие вещи происходят, потому что, когда вы delete this , член pi унициализирован, что приводит к деструктору, пытающемуся удалить оборванный указатель.

    
ответ дан visitor 12.08.2011 в 13:54
источник
-1

Плохая практика использования delete this. Однако, если она используется, необходимо учитывать следующие точки.

1) оператор delete работает только для объектов, выделенных с использованием нового оператора. Если объект создается с помощью new, мы можем удалить его, иначе поведение не определено.

  class A {
   public:
    void fun(){
     delete this;
   }
  };

 int main(){
 /* Following is Valid */
   A *ptr = new A;
   ptr->fun();
    ptr = NULL // make ptr NULL to make sure that things are not accessed using ptr. 


   /* And following is Invalid: Undefined Behavior */
    A a;
    a.fun();

 return 0;
}

2) После удаления этого действия любой элемент удаленного объекта не должен быть доступен после удаления.

 class A {
   int x;
  public:
    A() { x = 0;}
     void fun() {
      delete this;

    /* Invalid: Undefined Behavior */
    cout<<x;
  }
 };
    
ответ дан asad_nitp 14.12.2016 в 08:58
источник
  • почему все это смело? –  slawekwin 14.12.2016 в 09:05
  • полужирный - это сексуально, вы знаете :) –  asad_nitp 15.12.2016 в 11:23