2

I was checking my codes with valgrind and it found a memory leak. I didn't understand why it happened. Instead of putting my main code, I made a similar program to check whether my other allocations(char array etc.) cause the problem or classes cause this.

class zoo{
public:
    int x;
    zoo(int a){x = a;};
};

class doo:public zoo{
public:
    int y;
    doo(int a,int b):zoo(a){y = b;};
};

class foo : public doo{
public:
    String z;
    foo(int a, int b, const char *c):doo(a,b){
        z = c;
    };
};

zoo * something(const char * str){
    return (zoo *) new foo(1,2,str);
}
int main() {
    zoo * ex = something("blabla:sometext:blabla:overflow:message");
    cout<<"msg:"<< ((foo*)ex)->z<<endl;
    delete ex;
    return 0;
}

Nothing fancy in the code. There are base classes and I want to get a pointer in the last class as the pointer of the first base class.

When I compile this valgrind shows 4 allocs 3 frees.

What is wrong with this code ? Perhaps I misunderstood the concept of inheritance. Yet when I call the something function as

something("blabla")

No error is printed.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
fbgencer
  • 43
  • 6
  • 6
    You need to declare a virtual destructor. – Vlad from Moscow Mar 11 '20 at 20:27
  • 1
    `(zoo *)` in `(zoo *) new foo(1,2,str);` is not necessary and should be removed. It may hide errors in the future. Additionally `(foo*)` should be a `dynamic_cast(ex)` instead. C style casts like `(foo*)` and `(zoo*)` should be avoided and considered dangerous. If you *really* need a cast, use the weaker and more explicit C++ casts instead. – François Andrieux Mar 11 '20 at 20:29
  • Yes virtual destructor solved the issue @VladfrromMoscow. I am guessing when I give a small string Valgrind somehow sees it is freed. – fbgencer Mar 11 '20 at 20:32
  • @fbgencer That is probably because the compiler uses [short string optimization](https://stackoverflow.com/questions/21694302/what-are-the-mechanics-of-short-string-optimization-in-libc), where a small array is used instead of dynamically allocating memory for the string. – PaulMcKenzie Mar 11 '20 at 20:40

1 Answers1

3

As the base class has no virtual destructor then in this statement

delete ex;

there is called only the destructor of the class zoo according to the static type of the pointer. Sub-objects of the object of the type foo created in this statement

return (zoo *) new foo(1,2,str);

are not destructed.

You could at least define the destructor in the class zoo like

class zoo{
public:
    int x;
    zoo(int a){x = a;};
    virtual ~zoo() = default;
};
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335