Reputation: 26429
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
Reputation: 226
It's perfectly valid and also common practice, e.g. for implementing ref-counting (see MS COM's IUnknown)
Upvotes: 0
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
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
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
Reputation: 137890
Objects can destroy themselves. I don't see how being a virtual method changes anything.
Upvotes: 1