liveBook · Manning

Destructor

As explained in 100 C++ Mistakes and How to Avoid Them

A destructor is a C++ special member function that runs when an object is destroyed to release owned resources and perform cleanup.

A destructor is a C++ special member function that runs when an object is destroyed. It releases owned resources, such as dynamic memory, file handles, sockets, or database connections, and preserves the class invariant. section 7.6 section 10.0

Avoid these practical destructor mistakes:

  • Failing to release an owned dynamic resource leaks it when the object leaves scope. section 7.6
  • Deleting a derived object through a base pointer without a virtual destructor creates undefined behavior and can skip derived cleanup. section 8.8
  • Combining RAII ownership with manual deletion of the same pointer can cause a double free. section 10.5
  • Calling exit bypasses stack unwinding, so destructors do not run and acquired resources can leak. section 5.9

A destructor belongs with the copy constructor and copy-assignment operator when a class directly manages dynamic or limited resources. Copying must preserve ownership rules rather than merely copying pointer values. Modern ownership types can reduce the need for handwritten cleanup, but copying and assignment still require deliberate semantics. section 7.6 section 10.5

Polymorphic deletion

A Shape owns a Point and declares a virtual area function. If Shape has an ordinary destructor, deleting a Square through Shape* prints only ~Shape; Square's allocated side is not cleaned up. Declaring virtual ~Shape() makes deletion run ~Square followed by ~Shape. section 8.8

Listing 8.16 A base class with virtual destructor
class Point {
private:
    double x;
    double y;
public:
    Point(double x, double y) : x(x), y(y) {}
};
 
class Shape {
private:
    Point* location;
public:
    Shape(double x, double y) : location(new Point(x, y)) {}
    virtual ~Shape() { delete location;                     #1
        std::cout << "~Shape\n"; }    
    virtual double area() const = 0;
};
 
class Square : public Shape {
private:
    double* side;
public:
    Square(double side, double x, double y) : Shape(x, y),
        side(new double(side)) {}
    ~Square() { delete side;  std::cout << "~Square\n"; }
    double area() const { return *side * *side; }  // still looks weird
};
 
int main() {
    Shape* s = new Square(2.5, 0, 0);  // place at origin
    std::cout << s->area() << '\n';
    delete s;
    return 0;
} 

Compare the corrected base-class destructor with the polymorphic deletion example and observe the destruction order. section 8.8

RAII makes destruction the automatic cleanup point: acquire the resource during construction, transfer ownership clearly, and let scope exit handle normal and exceptional paths. Test both paths, especially when maintaining legacy code. section 10.5 section 5.9

How 100 C++ Mistakes and How to Avoid Them covers it

How deep it goes
Explains cleanup, ownership, virtual dispatch, RAII, and exception paths through worked examples, while deferring complete class redesign.
Examples
Uses Page ownership, Shape and Square deletion, Grades arrays, and a database Connection to demonstrate cleanup failures and corrections.
What it assumes
Assumes basic classes, constructors, pointers, scope, inheritance, and exceptions while teaching resource ownership through concrete failures.
What you can do after
Diagnose leaks, double frees, skipped cleanup, and unsafe polymorphic deletion; apply virtual destructors and RAII ownership.
How it connects
Connects destructors with resource management, RAII, copy constructors, copy assignment, exceptions, inheritance, and polymorphism.

Also explained in

Compare how 3 books explain destructor →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 C++ Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.