5

I am using dynamic memory allocation in my code, and am running into issues when trying to delete a pointer to a subclass. I find that the memory originally allocated is not freed when I use the delete keyword. The functionality works fine with the original base class.

This is an issue because I'm running the code on an arduino and the RAM gets eaten up quickly then crashes.

Here's some example code:

class Base
{
public:
    Base(){
        objPtr = new SomeObject;
    }
    ~Base(){
        delete objPtr;
    }
    SomeObject* objPtr;
};

class Sub : public Base
{
public:
    Sub(){
        objPtr = new SomeObject;
    }
};



// this works fine
int main()
{
    for (int n=0;n<100;n++) // or any arbitrary number
    {
        Base* basePtr = new Base;
        delete basePtr;
    }
    return 0;
}

// this crashes the arduino (runs out of RAM)
int main()
{
    for (int n=0;n<100;n++) // or any arbitrary number
    {
        Sub* subPtr = new Sub;
        delete subPtr;
    }
    return 0;
}

I imagine it has something to do with the syntax of the destructor in the base class. Even if I make a custom destructor for the subclass, the same issues occur.

Any ideas?

ryantuck
  • 6,146
  • 10
  • 57
  • 71

5 Answers5

6

In C++, constructors are called upwards in the hierarchy, that is, when you create Derived, Base() is executed before Derived(). This means that you are running objPtr = new SomeObject; twice, and only deleting it once.

You should also make your base class destructor virtual, especially if you will ever delete Derived instances from a Base ptr.

Community
  • 1
  • 1
congusbongus
  • 13,359
  • 7
  • 71
  • 99
3

You should make the base class' destructor virtual.

virtual ~Base(){
    delete objPtr;
}
TieDad
  • 9,143
  • 5
  • 32
  • 58
  • This will only fix half of the leaks – the other half will still leak because the allocation made in `Base`'s constructor is never deleted. – ildjarn Mar 22 '13 at 01:19
  • @ildjarn just to be pedantic, his example won't be affected by virtual base destructors anyway, because the example doesn't delete derived objects using base ptrs. http://stackoverflow.com/questions/1123044/when-should-your-destructor-be-virtual#1123159 – congusbongus Mar 22 '13 at 01:26
  • @CongXu : Quite true, and pedantry is always appreciated. :-] – ildjarn Mar 22 '13 at 01:27
1

Sub::Sub() constructor allocates a second extra SomeObject after a first one was allocated by Base::Base() super constructor and the second allocated pointer is assigned to objPtr provoking a leak.

Note: Base::Base() is implicitly called by Sub::Sub()

Solution: just remove needless allocation in Sub::Sub()

Another suggestion: make your Base destructor virtual as is recommended with inheritance

virtual ~Base(){
    delete objPtr;
}
0

When you create the derived class it calls the Base class constructor first and then Subs constructor, you can see this here:

class Base
{
public:
    Base(){
       std::cout << "Base() ctor" <<std::endl ;
        objPtr = new int;
    }
    ~Base(){
        delete objPtr;
    }
    int* objPtr;
};

class Sub : public Base
{
public:
    Sub(){
       std::cout << "Sub() ctor" <<std::endl ;
    objPtr = new int;
    }
};

So you end up calling new twice once in Base and then the second time in Sub. The memory allocated in Base is then lost and you have a leak. You also need to make the destructor virtual for it to work correctly with derived classes.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
0

Memory for that pointer is allocated twice. So you will never free all the memory you new for it. Just make the pointer a private member and allocate it only in base class.

JeromeCui
  • 39
  • 6