2

Here is an example for explaining virtual destructor.(see http://www.geeksforgeeks.org/g-fact-37/) I modify the code based on that example, and have a question about memory leak.

Suppose Base class has a variable of int num, Derived class has variable of float money.

When delete base_ptr;is called, since destructor of base class is virtual, ~derived() should be called first and then ~Base().

My question is "can function delete is smart enough so that it would free the memory allocated for both int num(Base Class) and float money(Derived Class)?

I think base_ptr is the pointer of type Base*, so it might only free the amount of memory needed for Base class. However, it seems that both int and float would be freed even if base_ptr is pointing type of Base class. If it is the case, would it lead to memory leak if we make ~Base() a non-virtual destructor? With a non-virtual destructor of ~Base(), we would miss the call of ~Derived(). Because nothing is dynamically allocated "within" both Base Class and Derived Class, it seems that ~Derived() does not actually free any memory at all, and function of delete would free both memory of int num and float money.

#include <iostream>
using namespace std;

class Base {
public:
    int num;

 Base(int n):num(n){
    cout<<"Base::Constructor\n";
 }
    virtual ~Base(){
    cout<<"Base::Destructor\n";
 }
};

class Derived : public Base {
private:
  float money;
public:
 Derived(int n, float m):Base(n),money(m){
    cout<<"Derived::Constructor\n";
 }
 ~Derived(){
    cout<<"Derived::destructor\n";
 }
};



int main() {
    Base *base_ptr = new Derived(1,200.0);
    delete base_ptr;
    return 0;
}
jaedong
  • 47
  • 6
  • This code is fine, but it would be undefined behaviour if the Base destructor were not virtual – M.M Mar 16 '17 at 21:28
  • First off, without the virtual destructor the code would have undefined behaviour, and there's little point debating the colour of the invisible unicorn. Second, before you ask whether the program would "only free a part of the memory", consider how you use `malloc` and `free`, and ask yourself how you tell `free` how much of the memory you want to have deallocated. – Kerrek SB Mar 16 '17 at 21:29
  • The C++ standard explicitly states that deleting a derived class instance through a base class pointer is undefined behavior. Trying to figure out when you can "fool the system" doesn't seem to be of worth. – PaulMcKenzie Mar 16 '17 at 21:40

1 Answers1

5

What you are describing is Undefined Behavior, which means any nasty stuff could go wrong, not just memory leaks.

But in practice, if the inheritance is not virtual, the derived class has no other base classes, and the derived class has no members with non-trivial destructors, you'll probably get the Base::~Base() destructor invoked and then operator delete called on the pointer. The operator delete(void*) function just takes a pointer and frees up all the memory it pointed at, so no "memory leak" there.

aschepler
  • 70,891
  • 9
  • 107
  • 161
  • 1.So 'delete' would always free the memory being initially allocated by 'new', even it cast to another type later? For example, int* ptr = new int(5); delete (char*)ptr; would still free the memory allocated for int rather than only for char? – jaedong Mar 16 '17 at 22:05
  • 2.I think the order of execution would be (with virtual destructor) 1) ~Derived(); and it would make varible float money kind of "undefined" but it does not actually "free" the memory allocated for float money. 2) ~Base(); it would make variable int num "undefined" and still not free any memory. 3)delete would eventually free memory both for base class and derived class being allocated initially by new. Is it right? I think that is 2 subtle points I need to understand. – jaedong Mar 16 '17 at 22:16
  • @jaedong - You are trying too hard. :-) Despite the similar names, the `delete` operator defined by the language and `operator delete(void*)` defined in the library are two different things. In `delete ptr` you need to have the pointer returned from `new`, and with the correct type. Otherwise how do we know which destructor(s) to call? When `operator delete(void*)` is called in part 3), the memory is untyped, just as with `free`, and the runtime magically knows the size anyway (in one of several possible ways, none of which is described by the C++ standard). – Bo Persson Mar 16 '17 at 23:24