SigTerm
SigTerm

Reputation: 26429

Indirectly destroying object from it's own virtual method. Is it a defined behavior?

Am I allowed to indirectly destroy object from within object's own virtual method? Is it a "defined behavior" (as long as I'm not trying to access anything after destroying the object)?
Example:

#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;
}

Output:

selfdestruct
clear
child destroyed
child is 0x00000000

If this is not a defined behavior, what can I do instead?

Upvotes: 1

Views: 302

Answers (5)

smocoder
smocoder

Reputation: 226

It's perfectly valid and also common practice, e.g. for implementing ref-counting (see MS COM's IUnknown)

Upvotes: 0

Chubsdad
Chubsdad

Reputation: 25537

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
}

So, self deletion, is always a tricky issue.

However, your question is about self destruction of the object and not necessary deallocation of memory in which it is constructed.

This is safe only when an it is sure that the object has been constructed in a memory location using 'placement new'

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;
}

Upvotes: 0

John Dibling
John Dibling

Reputation: 101484

This basically boils down to a delete this; so the answer is yes, it's allowed.

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

Upvotes: 1

Billy ONeal
Billy ONeal

Reputation: 106609

Well, a virtual method can call delete this. After the call though, NOTHING ELSE THAT TOUCHES THAT OBJECT INSTANCE can be done, or you have invoked undefined behavior. That includes calling other methods (even non virtual methods), accessing any instance variable, or the like.

Your specific code above invokes undefined behavior because the Child object needs a virtual destructor.

However, any type of situation where an object needs to destroy itself is not the best of designs.

Upvotes: 4

Potatoswatter
Potatoswatter

Reputation: 137890

Objects can destroy themselves. I don't see how being a virtual method changes anything.

Upvotes: 1

Related Questions