Question

Section 16.15 of the C++ FAQ Lite discusses delete this and then mentions:

Naturally the usual caveats apply in cases where your this pointer is a pointer to a base class when you don't have a virtual destructor.

Why is this true? Consider this code:

class ISuicidal {
public:
    virtual void suicide() = 0;
};

class MyKlass : public ISuicidal {
public:
    MyKlass() {
        cerr << "MyKlass constructor\n";
    }

    ~MyKlass() {
        cerr << "MyKlass destructor\n";
    }

    void suicide() {
        delete this;
    }
};

Used thus:

int main()
{
    ISuicidal* p = new MyKlass;
    p->suicide();
    return 0;
}

In the call p->suicide(), the destructor of MyKlass is called as expected, even though ISuicidal has no virtual destructor.

To me this makes sense, because in MyKlass::suicide, the static type of this is known to be MyKlass*, so the correct destructor is invoked. This is easy to verify by placing typeid calls inside suicide.

So is the FAQ entry inaccurate, or am I misunderstanding it?

Was it helpful?

Solution

You are misunderstanding. Implement the suicide function (ie delete this) in ISuicidal and you will find that when the this pointer is a base class calling delete on it doesn't call the derived class's destructor.

OTHER TIPS

In your function suicide(), You are using delete this;
Here, the this pointer corresponds to the class MyKlass, as the function is defined in MyKlass and not ISuicidal, and therefore the destructor of MyKlass is called.

If you had defined the function in ISuicidal, then it would not call the destructor of MyKlass unless you declare a virtual destructor in ISuicidal.

the problem arises if you introduce another real class in the hierarchy that derives from MyClass (e.g. MyClass2).

class ISuicidal {
public:
    virtual void suicide() = 0;
};

class MyKlass : public ISuicidal {
public:
    MyKlass() {
       cerr << "MyKlass constructor\n";
    }

    ~MyKlass() {
        cerr << "MyKlass destructor\n";
    }

    void suicide() {
        delete this;
    }
};

class MyKlass2 : public MyKlass {
public:
    MyKlass2() {
        cerr << "MyKlass2 ctr"<<std::endl;
    } 

    ~MyKlass2() {
        cerr << "MyKlass2 dtr"<<std::endl;
    }
}

int main()
{
    MyKlass* p = new MyKlass2;
    delete p; //destructor of base class called, not the destructor of MyKlass2 because
              //the destructor is not virtual
    return 0;
}

class Child : public MyKlass { ~Child () {} };

ISuicidal* p = new Child;

p->suicide(); // ~Child() not called !

I think you're misunderstanding it. The issue occurs when you call delete this in the base class, that is when the this pointer has a type of pointer to the base class.

Naturally the usual caveats apply in cases where your this pointer is a pointer to a base class when you don't have a virtual destructor.

In your example this is not a pointer to the base class but rather a pointer to the derived class.

it's safe as long as you call the exact destructor of the instance (e.g. do not call the destructor of a base).

therefore, you can safely accomplish this by properly implementing suicide() for every subclass - or by creating an external deleter function which is accessible to this (or whatever manages the lifetime of this).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top