问题
According to the standard, polymorphism with a missing virtual destructor leads to undefined behavior. In practice, it really leads to the destructor for the derived class not being called when the parent class is deleted. However, does it also lead to memory leaks in any common compilers/systems? I'm particularly interested in g++
on Android/Linux.
Specifically, I'm referring to whether the deletion of memory for the derived class will somehow leak. Consider:
class Base {}
class Derived {
int x;
}
If I delete a Base*
to a Derived
, will I leak 4 bytes? Or does the memory allocator already know how many bytes to free based on the allocation?
回答1:
It certainly can do. Consider:
class A
{
public:
virtual void func() {}
};
class B : public A
{
public:
void func() { s = "Some Long String xxxxxx"; }
private:
std::string s;
// destructor of B will call `std::string` destructor.
};
A* func(bool b)
{
if (b)
return new B;
return new A;
}
...
A* a = func(true);
...
delete a;
Now, this will create a memory leak, as std::string s
in the B
object is not freed by A::~A
- you need to call B::~B
, which will only happen if the destructor is virtual.
Note that this applies to ALL compilers and all runtime systems that I'm aware of (which is all the common ones and some not so common ones).
Edit:
Based on the updated actual question: Memory de-allocation happens based on the allocated size, so if you can GUARANTEE that there NEVER is a single allocation happening because of the construction/use of the class, then it's safe to not have a virtual destructor. However, this leads to interesting issues if a "customer" of the base-class can make his/her own extension classes. Marking derived classes as final
will protect against them being further derived, but if the base class is visible in a header-file that others can include, then you run the risk of someone deriving their own class from Base
that does something that allocates.
So, in other words, in something like a PImpl
, where the Impl
class is hidden inside a source file that nobody else derives from, it's plausible to have this. For most other cases, probably a bad idea.
回答2:
A missing destructor will cause undefined behavior specifically because it's implausible for the compiler to know exactly what the side effects might be.
Think of it as the cleanup side of RAII. In that case, if you manage to not clean up despite claiming that you did, side effects might be:
- Leaked memory (you allocated something... when do you deallocate it now?)
- Deadlocks (you locked something... when do you unlock it now?)
- Sockets remaining open (you opened it sometime... but now when do you close it?)
- Files remaining open (you opened it sometime... but now when do you flush it?)
- Accessing invalid pointers (for example, you updated a pointer to some member... but now when do you unset it?)
- Your hard drive gets erased (technically this is a valid answer for any undefined behavior)
回答3:
This should cause Undefined Behaviour which means it might also cause memory leaks. In 5.3.5/3 (n4296 c++14) for delete
you have:
In the first alternative (delete object), 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. In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.
来源:https://stackoverflow.com/questions/31664064/missing-virtual-destructor-memory-effects