Косвенное уничтожение объекта из его собственного виртуального метода. Это определенное поведение? - PullRequest
1 голос
/ 13 августа 2010

Могу ли я косвенно уничтожить объект изнутри собственного виртуального метода объекта? Это «определенное поведение» (пока я не пытаюсь получить доступ к чему-либо после уничтожения объекта)?
Пример:

#include <memory>
#include <stdio.h>

using std::tr1::shared_ptr;

struct Child{
    virtual void selfdestruct() = 0;
    virtual ~Child(){
        fprintf(stderr, "child destroyed\n");

    }
};

typedef shared_ptr<Child> ChildPtr;

struct Parent{
    ChildPtr child;
    void clear(){
        fprintf(stderr, "clear\n");
        child = ChildPtr();
    }   
    Parent();
};

struct DerivedChild: public Child{
    Parent* parent;

    virtual void selfdestruct(){
        fprintf(stderr, "selfdestruct\n");
        if (parent)
            parent->clear();
    }

    DerivedChild(Parent* p)
    :parent(p){
    }
};

Parent::Parent(){
    child = ChildPtr(new DerivedChild(this));
}


int main(int argc, char** argv){
    Parent p;
    p.child->selfdestruct();    
    fprintf(stderr, "child is 0x%08x\n", p.child);
    return 0;
}

Выход:

selfdestruct
clear
child destroyed
child is 0x00000000

Если это не определенное поведение, что я могу сделать вместо этого?

Ответы [ 5 ]

4 голосов
/ 13 августа 2010

Ну, виртуальный метод может вызвать delete this.Тем не менее, после вызова НИЧЕГО, ЧТО НЕ ПРИКЛЮЧАЕТ ЭТО ОБЪЕКТ ОБРАЗОВАНИЯ, или вы вызвали неопределенное поведение.Это включает в себя вызов других методов (даже не виртуальных), доступ к любой переменной экземпляра и т. П.

Ваш приведенный выше код вызывает неопределенное поведение, поскольку объекту Child необходим виртуальный деструктор.

Однако любая ситуация, в которой объект должен сам себя уничтожить, не является лучшим из замыслов.

1 голос
/ 13 августа 2010

Это в основном сводится к delete this;, поэтому ответ - да, это разрешено.

void clear(){
    fprintf(stderr, "clear\n");
    child = ChildPtr();
}   
1 голос
/ 13 августа 2010

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

0 голосов
/ 13 августа 2010

Это совершенно справедливо, а также обычная практика, например, для реализации подсчета ссылок (см. IUnknown MS COM)

0 голосов
/ 13 августа 2010
struct X{
   X() {f();}
   virtual void f(){delete this;}
};

int main(){
   //X x;        // evil, 'delete this' is an error, because 'new' itself was not done
   //x.f();    

   X *p = new X; // Ok, but 'p' now points to an already deleted memory
   p->f();       // evil, double delete
}

Таким образом, самоуничтожение - это всегда сложная проблема.

Однако ваш вопрос касается самоуничтожения объекта и необязательного освобождения памяти, в которой он построен.

Это безопасно только в том случае, если есть уверенность, что объект был создан в ячейке памяти с использованием «размещения нового» * ​​1006 *

struct X{
   X() {f();}
   ~X(){}
   virtual void f(){this->~X();}    // here an object destroys itself, but no memory deallocation is done. This is fine and safe as well.
};

int main(){
   char *p = new char [sizeof(X)];  // assume alignment requirements are met
   X *px = new (p) X();
   delete [] p;
}
...