2

If I have the below two classes:

#include <cstdlib>

class Parent
{
    protected:
        int* mem = (int*) std::malloc(5); // pointer to dynamically-stored object
    public:
        Parent() {};
        virtual ~Parent()
        {
            delete(mem);
        }
};

class Child: public Parent
{
    public:
        Child() {};
        ~Child()
        {
            delete(mem);
        }
};

int main(void)
{
    Child* c = new Child();
    delete(c);
}

Shouldn't calling delete on an instance of the Child class cause a segmentation fault, since the parent's destructor is also automatically called after the child destructor? And if so, would the solution be for the Child class to only deal with freeing dynamically-allocated memory "owned" by Child class (i.e. not delete mem in Child's destructor and leave it to Parent to deal with it) ?

I ran my main function and expected a segmentation fault to occur since mem was being freed twice - once in Child's destructor and again in the Parent destructor. No error occurred, which I found surprising. Can anyone please explain why?

wohlstad
  • 12,661
  • 10
  • 26
  • 39
  • 4
    This program exhibits undefined behavior, by way of applying `delete` operator to a pointer that was not obtained with `new`. The complement for `std::malloc` is `std::free` – Igor Tandetnik Mar 01 '23 at 05:11
  • 2
    And yes, it further exhibits undefined behavior by way of double-deleting the same pointer. Undefined behavior is undefined, it doesn't predictably cause a segmentation fault. "Seems to work" is one possible manifestation of undefined behavior. – Igor Tandetnik Mar 01 '23 at 05:12
  • I see, so double-deleting the same pointer exhibits undefined behaviour. I'm taking a class in Object Orientation right now so I am still new to this. Would the correct way to implement the above two classes be for the Parent class to handle freeing of "mem" on its own? What if the parent class were purely virtual? – Ye Naing Oo Mar 01 '23 at 05:21
  • 2
    Yes the parent should be the only one freeing the memory it allocated. – wohlstad Mar 01 '23 at 05:25

2 Answers2

7

Your code has 2 issues:

  1. Memory allocated with malloc should be released with free, not with delete.
  2. The Child should not attempt to free memory that it did not allocate. When the Parent destructor will execute it will attempt to release memory that was already released by the Child.

Both these issues cause UB (Undefined Behavior), meaning anything can happen.

wohlstad
  • 12,661
  • 10
  • 26
  • 39
2

The problem is not that both destructors are called, which is the designed behavior; the problem is that you are deleting a pointer twice (double-free).

Since you are managing the pointer in the base class it is natural that only the base destructor is responsible for the destruction. Although other designs are possible. (For example, the child deletes de pointers and sets it to null so the base destructor --called later-- cannot delete it again, or really forget about all this an use a std::unique_ptr<int>).

alfC
  • 14,261
  • 4
  • 67
  • 118