Why is the following code causing a memory leakage?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
using namespace std;

class Base {
public:

    Base() {
    }

    ~Base() {
        cout << "Base" << endl;
    }
};

class Derived : public Base {
public:

    Derived() {
    }

    ~Derived() {
        cout << "Derived" << endl;
    }
};

int main(int argc, char* argv[]) {
    Base * v[5];
    for (int i = 0; i < 5; i++) {
        v[i] = new Derived();
        delete v[i];
    }
    return 0;
}


(Main function)
My teacher told me that the following code is causing a memory leakage. I still don't understand why? He said that I have to delete v explicitly. I thought I already did that with ''delete v[i]'' ..
The problem is that you are creating a new Derived class, then deleting via a Base*. This means that the compiler will call ~Base ONLY, not ~Derived, which means you could be failing to free resources that Derived created.
you need virtual ~Base()

because v is an array of Base*, when you call delete v[i] only ~Base() is called. What you want is ~Derived() ==> polymorphic behavior ==> virtual dtor
Your teacher is wrong. This code has no memory leakage provided that sizeof( Base ) == sizeof( Derived ). For example if to compile your code with MS VC++ 2010 then the both sizes are equal to 1 because the classes have no data members.
Though it would be better if the destructor of Base had function specifier virtual.
This is undefined behavior. Anything at all can happen, doesn't matter what the sizes are.
Last edited on
It is undefined behaviour only because the standard does not says what are the sizes of empty base and empty derived classes. But if they are equal there is no any memory leakage.
no vlad, it's undefined because the standard says so (and when the standard says something, compiler writers listen)
Let consider the situation step by step. The Base class constructor is called. There is nothing undefined in calling the base constructor. It does nothing because there is no data members. The next step the compiler frees the memory. What is the memory size? The same as of the derived class. So there is no any undefined behaviour.
The Standard says about undefined behaviour only because it does not define sizes of empty base and derived classes. it considers general cases without any exceptions. Nevertheless in the original post there is no any memory leakage and undefined behaviour if the sizes are equal. The behaviour is predictable and all compilers will behave the same way.
Last edited on
Let consider the situation step by step. The Base class constructor is called. There is nothing undefined in calling the base constructor. It does nothing because there is no data members. The next step the compiler frees the memory. What is the memory size? The same as of the derived class. So there is no any undefined behaviour.


I'm sure you're already aware of the fact that undefined behavior can manifest itself as expected behavior. That doesn't make it any less undefined. The code in question invokes undefined behavior because the derived class destructor is not invoked and not because they are empty classes.

Why don't you apply the same logic to the following code with empty classes?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <map>

struct A ;

std::map<A*, int *> store ;

struct A
{
    A( int* p ) ;
    ~A() ; 
};

A::A(int* p)
{
    store.insert(std::make_pair(this, p)) ;
}

A::~A()
{
    delete [] store[this] ;
    store.erase(store.find(this)) ;
}

struct B : public A
{
    B( int* p ) : A(p) {}
    ~B() { store[this] = nullptr ; }
};

int main()
{
    std::cout << sizeof(A) << '\n' ;
    std::cout << sizeof(B) << '\n' ;

    int array[16] ;

    A * ptr = new B(array) ;
    delete ptr ;
}
vlad wrote:
So there is no any undefined behaviour.

As you like to say, read the standard. The paragraph that describes the delete expression, it is very clear.
Last edited on
Your example has nothing common with the discussed question. It simply demonstrates invalid code.

That to be clear we were discussing classes with trivial constructors and destructors or at least with that that do nothing except printing some messages.

As you can see I always underlined that the destructor does nothing. Consider standard-layout classes. There was not such a notion before 2011 in the C++ Standard. I will not wonder if in future there will be an interest to underline that standard-layout classes can be destructed by using any destructor of a derived class. I do not see any undefined behavior for such classes.
Last edited on
vlad from moscow wrote:
Your example has nothing common with the discussed question. It simply demonstrates invalid code.

Neither example demonstrates invalid code, but they both exhibit undefined behavior. All that is required in either example to fix it is to make the destructor virtual.


vlad from moscow wrote:
That to be clear we were discussing classes with trivial constructors and destructors or at least with that that do nothing except printing some messages.

You failed to mention that little qualification in:
It is undefined behaviour only because the standard does not says what are the sizes of empty base and empty derived classes.



vlad from moscow wrote:
As you can see I always underlined that the destructor does nothing.

No, I don't, and the standard doesn't make such a distinction with regards to this undefined behavior, either. But we all know you know better than the standard!


Just in case someone is stumbling on this thread wondering what the standard has to say on this:
... if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined.
... which can be found in 5.3.5

Topic archived. No new replies allowed.