C/C++ Arena

Step 5 of 9

Virtual destructors

Here's why the base class of a hierarchy always has a virtual destructor. When you delete an object through a base pointer (which is what unique_ptr<Base> does when it goes away), the destructor call follows the same rule as any other member function:

#include <iostream>
#include <memory>
#include <string>

struct Connection {
    virtual ~Connection() { std::cout << "close socket\n"; }
};

struct TlsConnection : Connection {
    std::string session = "keys";
    ~TlsConnection() override { std::cout << "wipe " << session << "\n"; }
};

int main() {
    std::unique_ptr<Connection> c = std::make_unique<TlsConnection>();
    std::cout << "using connection\n";
}
using connection
wipe keys
close socket

The order

Construction goes base first, then derived: the derived constructor relies on its base part already existing. Destruction goes in reverse: derived first, then base. The output shows the derived cleanup (wipe keys) before the base cleanup (close socket).

If you removed the virtual from ~Connection, the wipe keys line would disappear. In real code that's a leaked session key, a leaked buffer, or an open file.

The rule

If a class has any virtual function, give it a virtual destructor. virtual ~Base() = default; is enough when there's nothing to clean up in the base itself.

Your turn: the program should print:

+ base
+ derived
- derived
- base

but - derived is missing. Fix it with one keyword.

Previous: Polymorphic containers Next: Calling the base version, and protected