iDevGames Forums
C++: is "delete (base_class*)this;" safe? - Printable Version

+- iDevGames Forums (http://www.idevgames.com/forums)
+-- Forum: Development Zone (/forum-3.html)
+--- Forum: Programming Languages & Scripting (/forum-8.html)
+--- Thread: C++: is "delete (base_class*)this;" safe? (/thread-2633.html)



C++: is "delete (base_class*)this;" safe? - sealfin - May 16, 2008 07:22 AM

Okay, I've a base class containing a lot of resources and a simple reference counting system for allocating or deallocating those resources as necessary, shared between several derived classes.

I'd failed to consider that if an exception occurs in the constructor of any of the derived classes, the destructor of the base class won't be invoked, and the reference counting system will either at best hold an incorrect (+1) value, or at worst fail to deallocate the resources.

I think that this problem can be solved by catching any exception which occurs in the constructors of the derived classes, invoking "delete (base_class*)this;", and rethrowing the exception.

I'm just wondering whether anybody can confirm whether this is a safe technique? The quick and dirty test below seems to give a safe result, but searching hasn't given me a definitive answer, just the usual dire warnings about mixing C and C++ memory management...

Code:
#include <stdio.h>

class A
{
    private:
        static unsigned int mg_noOfInstances;
        // Lots of static pointers.

    public:
        A( void )
        {
            // Allocate static pointers if mg_noOfInstances == 0, throw exception if mg_noOfInstances == UINT_MAX.
            mg_noOfInstances ++;
            printf( "A()\nmg_noOfInstances == %d\n", mg_noOfInstances );
            return;
        };

        virtual ~A( void )
        {
            mg_noOfInstances --;
            // Deallocate static pointers if mg_noOfInstances == 0.
            printf( "~A()\nmg_noOfInstances == %d\n", mg_noOfInstances );
            return;
        };
};

unsigned int A::mg_noOfInstances = 0;

class B : private A
{
    public:
        B( void )
        {
            printf( "B()\n" );
            // Oh noes! We've encountered an exception; better clean ourselves up before we die...
            delete (A*)this;
            throw "Oh noes!";
        };
};

int main( void )
{
    B *b = new B();
    return 0;
}

Terminal.app Wrote:A()
mg_noOfInstances == 1
B()
~A()
mg_noOfInstances == 0
Abort trap

N.b. I know I could circumvent this problem by making the base class an attribute of the derived classes, and if there's no alternative, I will; I'd just prefer a 'prettier' architecture if at all possible...


C++: is "delete (base_class*)this;" safe? - MattDiamond - May 16, 2008 11:23 AM

http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.3

Short answer: don't throw exceptions in destructors, don't expect to safely be able to handle exceptions in destructors.


C++: is "delete (base_class*)this;" safe? - OneSadCookie - May 16, 2008 02:34 PM

The destructor of your base class *will* be called if the constructor of a subclass throws:

Code:
extern "C" void puts(char const *);

class A {
public:
    virtual ~A() { puts("~A"); }
};

class B : public A {
public:
    B() { throw 1; }
    ~B() { puts("~B"); }
};

main() { try { B b; } catch(int) { puts("gotcha"); } }

Code:
keith$ g++ test.cc
keith$ ./a.out
~A
gotcha

... so I don't know what your problem is.


C++: is "delete (base_class*)this;" safe? - sealfin - May 16, 2008 03:26 PM

Ugh... Thanks OSC, I finally figured out the difference between your and my code which was causing the difference in behaviour: that the destructor of the base class is only invoked if the exception is caught, which of course is obvious in hindsight Blush