C++ by Example
C++ by Example

Constructors and Destructors

2 min read

Constructors and Destructors

Constructors initialize objects. Destructors clean up when objects are destroyed. Together they implement RAII and control the full lifecycle of a type.

Default constructor

A constructor with no parameters (or all-defaulted parameters) is the default constructor. It is called when you create an object without arguments:

#include <iostream>

class Timer {
    double elapsed;
public:
    Timer() : elapsed(0.0) {
        std::cout << "Timer started\n";
    }

    double get() const { return elapsed; }
};

int main() {
    Timer t;     // calls Timer()
    Timer arr[3]; // calls Timer() three times
}

If you declare no constructors, the compiler generates a default constructor. If you declare any constructor, the compiler no longer generates one.

Member initializer list

Members should be initialized in the initializer list, not assigned in the body. It is more efficient (avoids default-constructing then assigning) and is required for const members and references:

class Person {
    const std::string name;
    int age;
public:
    Person(std::string n, int a) : name(std::move(n)), age(a) {}
};

Members are initialized in declaration order, not the order they appear in the initializer list. Keep the two orders consistent to avoid surprises.

Destructor

A destructor has the same name as the class prefixed with ~. It takes no parameters and returns nothing:

#include <iostream>

class Resource {
    int id;
public:
    explicit Resource(int i) : id(i) {
        std::cout << "Resource " << id << " acquired\n";
    }
    ~Resource() {
        std::cout << "Resource " << id << " released\n";
    }
};

int main() {
    Resource r1(1);
    {
        Resource r2(2);
    }   // r2 destroyed here
}       // r1 destroyed here
// Output:
// Resource 1 acquired
// Resource 2 acquired
// Resource 2 released
// Resource 1 released

Destructors run in reverse order of construction.

Delegating constructors (C++11)

A constructor can call another constructor of the same class:

class Rect {
    double w, h;
public:
    Rect(double w, double h) : w(w), h(h) {}
    Rect(double side) : Rect(side, side) {}   // delegates to the first
    Rect() : Rect(1.0) {}                      // delegates to the second
};

= default and = delete

= default asks the compiler to generate the standard implementation. = delete forbids a function entirely:

class NonCopyable {
public:
    NonCopyable() = default;
    ~NonCopyable() = default;

    NonCopyable(const NonCopyable&) = delete;            // no copy
    NonCopyable& operator=(const NonCopyable&) = delete; // no copy assign
};

Marking copy operations = delete prevents accidental copying of types that own resources — file handles, mutexes, sockets.

explicit constructors

A single-parameter constructor can be called implicitly in conversions. Mark it explicit to forbid this:

class Meters {
    double value;
public:
    explicit Meters(double v) : value(v) {}
};

void print_distance(Meters m);

print_distance(5.0);           // compile error: no implicit conversion
print_distance(Meters(5.0));   // OK: explicit construction

explicit prevents surprising implicit conversions that could silently change program meaning.

C++ by Example
C++ by Example

Learn modern C++ through working code. Each chapter introduces one concept — variables, functions, classes, templates, smart pointers, concurrency — with a clear example, a line-by-line explanation, and notes on how it applies in real programs.

View book →