Skip to content

Instantly share code, notes, and snippets.

@jpmec
Created July 27, 2013 00:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jpmec/6093068 to your computer and use it in GitHub Desktop.
Save jpmec/6093068 to your computer and use it in GitHub Desktop.
A simple example demonstrating C++ virtual destructors and the pitfalls if they are not used.
/** An example of a virtual destructor.
*
* Compile with:
* g++ -Wall test_cpp_virtual_destructor.cpp -o test_cpp_virtual_destructor
*/
#include <iostream>
using namespace std;
/// A class with a non-virtual destructor.
struct NonVirtualDestructor
{
~NonVirtualDestructor(void)
{
cout << "NonVirtualDestructor::~NonVirtualDestructor" << endl;
}
// Simple method to allow us to do something with the class instance.
// Otherwise compiler might optimize out.
void Foo(void)
{
cout << "NonVirtualDestructor::Foo" << endl;
}
};
/// A class derived from a base class with non-virtual destructor.
struct DerivedNonVirtualDestructor : NonVirtualDestructor
{
~DerivedNonVirtualDestructor(void)
{
cout << "DerivedNonVirtualDestructor::~DerivedNonVirtualDestructor" << endl;
}
};
/// A class with a virtual destructor.
struct VirtualDestructor
{
virtual ~VirtualDestructor(void)
{
cout << "VirtualDestructor::~VirtualDestructor" << endl;
}
// Simple method to allow us to do something with the class instance.
// Otherwise compiler might optimize out.
void Foo(void)
{
cout << "VirtualDestructor::Foo" << endl;
}
};
/// A class derived from a base class with virtual destructor.
struct DerivedVirtualDestructor : VirtualDestructor
{
// Note, that destructor is not defined with explicit virtual keyword.
// It will still be virtual because base class destructor is virtual.
~DerivedVirtualDestructor(void)
{
cout << "DerivedVirtualDestructor::~DerivedVirtualDestructor" << endl;
}
};
// Test DerivedNonVirtualDestructor in a local scope.
// Destructors are called for derived and base class.
// Expect output:
// NonVirtualDestructor::Foo
// DerivedNonVirtualDestructor::~DerivedNonVirtualDestructor
// NonVirtualDestructor::~NonVirtualDestructor
void test_DerivedNonVirtualDestructor_in_local_scope(void)
{
cout << endl << __FUNCTION__ << endl;
DerivedNonVirtualDestructor c;
c.Foo();
}
// Test DerivedVirtualDestructor in a local scope.
// Destructors are called for derived and base class.
// Expect output:
// VirtualDestructor::Foo
// DerivedVirtualDestructor::~DerivedVirtualDestructor
// VirtualDestructor::~VirtualDestructor
void test_DerivedVirtualDestructor_in_local_scope(void)
{
cout << endl << __FUNCTION__ << endl;
DerivedVirtualDestructor c;
c.Foo();
}
// Test dynamically allocated DerivedNonVirtualDestructor.
// Destructors are called for base class BUT NOT DERIVED CLASS!
// If the derived class had allocated new memory, the destructor would not be called
// in order to delete the memory. This could cause memory leaks!
//
// Expect output:
// NonVirtualDestructor::Foo
// NonVirtualDestructor::~NonVirtualDestructor
//
void test_DerivedNonVirtualDestructor_in_dynamic_memory(void)
{
cout << endl << __FUNCTION__ << endl;
NonVirtualDestructor* c = new DerivedNonVirtualDestructor();
c->Foo();
delete c;
}
// Test dynamically allocated DerivedVirtualDestructor.
// Destructors are called for base class and derived class.
// This is most often the desired behavior.
//
// Expect output:
// VirtualDestructor::Foo
// DerivedVirtualDestructor::~DerivedVirtualDestructor
// VirtualDestructor::~VirtualDestructor
//
void test_DerivedVirtualDestructor_in_dynamic_memory(void)
{
cout << endl << __FUNCTION__ << endl;
VirtualDestructor* c = new DerivedVirtualDestructor();
c->Foo();
delete c;
}
int main(int argc, const char* argv[])
{
test_DerivedNonVirtualDestructor_in_local_scope();
test_DerivedVirtualDestructor_in_local_scope();
test_DerivedNonVirtualDestructor_in_dynamic_memory();
test_DerivedVirtualDestructor_in_dynamic_memory();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment