destructor / semantics of delete this

A

Alexander Stippler

Hi,

I have some question about the usage of delete. I have some reference
counted classes, all derived from SharedObject. It's destructor looks like
this:

~SharedObject()
{
if (--references_ == 0) {
delete this;
}
}

Now I'd like to know if
a) it's OK to use delete this (especially in the destructor)
and
b) my guess, about what happens, is correct.
In my understanding the destructor is entered and delete this is executed
(if "if" is entered of course). Delete, as far as I know, calls the
destructor of the object again, now the if-condition is false and the
storage is freed due to the first call of delete.
I may be absolutely wrong. I would not wonder. But what does really happen
and is it a good idea at all to use delete this.

regards,
alex
 
I

Ivan Vecerina

| I have some question about the usage of delete. I have some reference
| counted classes, all derived from SharedObject. It's destructor looks like
| this:
|
| ~SharedObject()
| {
| if (--references_ == 0) {
| delete this;
| }
| }

This won't work. Once the destructor is executed, it is too late to
try to cancel the destruction process.
You need to use a different approach:
class SharedObject
{
public:
SharedObject() : refCnt(1) {}
void addRef() { ++refCnt; }
void release() { if(!--refCnt) delete this; }
protected:
virtual ~SharedObject()=0; // abstract class
private:
int refCnt;
};
SharedObject::~SharedObject() {}

Such a base class is usually combined with a smart pointer.
+ templates are to be considered for type safety.

Note that reference-counted classes is a well studied subject in C++.
Make sure to read advice from Scott Meyers and others on the subject.
Also, existing implementations such as boost::shared_ptr definitely
are to be considered:
http://www.boost.org/libs/smart_ptr/shared_ptr.htm


| Now I'd like to know if
| a) it's OK to use delete this (especially in the destructor)
Yes in rare and specific cases -- but never in the destructor.

| b) my guess, about what happens, is correct.
| In my understanding the destructor is entered and delete this is executed
| (if "if" is entered of course). Delete, as far as I know, calls the
| destructor of the object again, now the if-condition is false and the
| storage is freed due to the first call of delete.
This leads to undefined behavior. Not only is it illegal to call the
destructor twice. But also, the call to 'delete' will attempt to free
memory (=> the same memory block will be freed twice, or the call
will attempt to free a stack-based address... not good at all).


I hope this helps,
 
C

Chris Theis

Alexander Stippler said:
Hi,

I have some question about the usage of delete. I have some reference
counted classes, all derived from SharedObject. It's destructor looks like
this:

~SharedObject()
{
if (--references_ == 0) {
delete this;
}
}

Now I'd like to know if
a) it's OK to use delete this (especially in the destructor)
and
b) my guess, about what happens, is correct.
In my understanding the destructor is entered and delete this is executed
(if "if" is entered of course). Delete, as far as I know, calls the
destructor of the object again, now the if-condition is false and the
storage is freed due to the first call of delete.
I may be absolutely wrong. I would not wonder. But what does really happen
and is it a good idea at all to use delete this.
As it's already been pointed out by Ivan it's not a good idea to use delete
this in a dtor. You will end up in a recursive call of the dtor which stops
after 2 iterations but still it's illegal to call the dtor of an object
twice. I'd recommend to read Scott Meyer's article from April 1998 in the
C++ Users Journal and there are countless others covering this topic. You
can furthermore refer to the FAQ 16.21 for a brief overview.

HTH
Chris
 
R

Rolf Magnus

Chris said:
As it's already been pointed out by Ivan it's not a good idea to use
delete this in a dtor. You will end up in a recursive call of the dtor
which stops after 2 iterations but still it's illegal to call the dtor
of an object twice.

Not only will the destructor be called twice, but the memory will be
released twice, unless the object wasn't dynamically allocated. I this
case, delete is called for an object that never came from new.
While, depending on the situation, some compilers may let you go away
with two destructor calls, the other thing almost always results in a
crash. Generally, none of those things are allowed in C++.
 
C

Chris Theis

Rolf Magnus said:
Not only will the destructor be called twice, but the memory will be
released twice, unless the object wasn't dynamically allocated. I this
case, delete is called for an object that never came from new.

You're of course right on this point, which I should have mentioned for
completeness.
While, depending on the situation, some compilers may let you go away
with two destructor calls, the other thing almost always results in a
crash. Generally, none of those things are allowed in C++.

If I get you correctly you indicate that there might be situations
("...almost always...") when calling delete twice on an object will not
result in a crash. Just out of curiosity could you give me an example.

Regards
Chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top