I spent over 2 hours finding this memory leak:
class Parent{
...
}
class Child:public Parent{
std::string str;
...
}
int main(){
Parent *ptr=new Child();
delete ptr;
}
I fixed it by moving the string into the parent class. Why did this memory leak happen? Shouldn't the child's members be deleted as well?
Memory leaks occur when new memory is allocated dynamically and never deallocated. In C programs, new memory is allocated by the malloc or calloc functions, and deallocated by the free function.
The memory leak occurs, when a piece of memory which was previously allocated by the programmer. Then it is not deallocated properly by programmer. That memory is no longer in use by the program. So that place is reserved for no reason. That's why this is called the memory leak.
C. To avoid memory leaks, memory allocated on heap should always be freed when no longer needed.
Memory leakage occurs in C++ when programmers allocates memory by using new keyword and forgets to deallocate the memory by using delete() function or delete[] operator. One of the most memory leakage occurs in C++ by using wrong delete operator.
This can happen because Parent
may not have a virtual destructor. Since you are creating a Parent*
(the base class) to a dynamically allocated derived class Child
, deleting the Parent*
which has no virtual destructor will cause undefined behaviour, but typically will result in the derived class not being destroyed.
From Scott Myers - Effective C++ Third Edition:
... if we delete Base class pointer with a non-virtual destructor, results are undefined. What typically happens at runtime is that the derived part of the object is never destroyed. This is an excellent way to leak resources, corrupt data structures, and spend a lot of time with a debugger. So any class with virtual functions should almost certainly have a virtual destructor.
class Parent{
};
class Child:public Parent{
public:
Child() : str("Child") {}
~Child() { std::cout << str << std::endl;};
std::string str;
};
int main(){
Parent *ptr=new Child();
delete ptr; // undefined behaviour: deleting a Base* to a Derived object where the Base has no virtual destructor
}
Parent
's destructor virtual
:class Parent{
public:
virtual ~Parent() {} // Will call derived classes destructors now as well
};
class Child:public Parent{
public:
Child() : str("Child") {}
~Child() { std::cout << str << std::endl;};
std::string str;
};
int main(){
Parent *ptr=new Child();
delete ptr;
// Child::~Child() has now been called.
}
See When to use virtual destructors? which probably explains it better than I did
Edit: Thank you to the @aschepler (in the question's comments), commenters below, and the answer to the linked question, I have updated the answer to better reflect that this is undefined behaviour. In my haste I didn't mention it, and only mentioned the typical behaviour
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With