Memory management

Perhaps the most annoying feature of C++ (or rather absence of it) is memory management. Whereas both Smalltalk and Eiffel offer automatic garbage collection, the C++ programmer is required to rely on hand-crafted memory management.
class A { 
\fbox{A}
public: A() { cout << "A"; } ~A() { cout << "A"; } }; class B : public A {
\fbox{B}
public: B() { cout << "B"; } ~B() { cout << "B"; } };

slide: Constructors and destructors

Memory management in C++ involves the use of constructors and destructors. In the following, we will look at some examples illustrating the order of invocation of constructors and destructors in relation to single and multiple inheritance.

The first example, given in slide 2-m-1, defines two classes (A and B, with B derived from A), each having a constructor and destructor writing the name of the class to standard output. An example of their use is:

  A* a = new B; delete a; 
ABA

B* b = new B; delete b;
ABBA

Recall that when creating an instance of a class, the constructors of the base classes (if any) are called first. This is exactly what happens above. However, contrary to what is expected, when deleting a, the destructor for B is not called, whereas it is invoked when deleting b.
class A { 
\fbox{A}
public: A() { cout << "A"; } virtual ~A() { cout << "A"; } };

slide: Virtual destructors

The remedy to this is to declare the destructor of A virtual, as in slide 2-m-2, since it dynamically invokes the destructor declared for the actual class type $(B) of the object referenced. The program fragment
  A* a = new B; delete a; 
ABBA

B* b = new B; delete b;
ABBA

now behaves as desired.
class C: public A { 
\fbox{C}
public: C() { cout << "C"; } ~C() { cout << "C"; } }; class D : public B, public C {
\fbox{D}
public: D() { cout << "D"; } ~D() { cout << "D"; } };

slide: Multiple inheritance

Multiple inheritance

When employing multiple inheritance, similar rules are followed, as depicted in slide 2-m-3.

However, one problem we may encounter here is that classes may have a common base class. Look at the following program fragment:

  D* a = new D(); delete a; 
ABACDDCABA

The outcome of creating and deleting a indicates that an instance of D contains two copies of A.
class B: virtual public A { 
\fbox{B}
public: B() { cout << "B"; } ~B() { cout << "B"; } }; class C: virtual public A {
\fbox{C}
public: C() { cout << "C"; } ~C() { cout << "C"; } };

slide: Virtual inheritance

Again, the remedy is to declare A to be virtually inherited by B and C, as depicted in slide 2-m-4. As reflected in the outcome of
  A* a = new D(); delete a; 
ABCDDCBA

instances of the derived class D then have only one copy of A.