C++ PROGRAMMING ยท 16 MIN STUDY

Constructors, destructors, and invariants

Initialize class objects safely, use member initializer lists, and understand object cleanup.

Learning objectives

  • Explain what constructors and destructors do.
  • Write constructors with member initializer lists.
  • Understand default and parameterized construction.
  • Connect class invariants with encapsulation.

Prerequisites: understand classes, data members, access control, and object creation. Review Classes and objects first.

Constructor: create a valid object

A constructor is a special member function called when an object is initialized. It has the same name as its class and no return type. Its job is to establish the object's initial state.

C++17
#include <string>

class Student {
private:
    std::string name;
    int age;
public:
    Student(const std::string& student_name, int student_age)
        : name(student_name), age(student_age) {}
};

The part after the colon is the member initializer list. It initializes members directly. This is preferred to default-constructing a member and assigning to it later. Members are initialized in the order they are declared in the class, not the order written in the initializer list.

Default construction

A default constructor can be called with no arguments. If you define a parameterized constructor, the compiler does not automatically provide the same implicit default constructor. If you need both, define or explicitly default the default constructor.

class Counter {
public:
    Counter() = default;
    explicit Counter(int start) : value(start) {}
private:
    int value{0};
};

Destructor: clean up

A destructor runs when an object's lifetime ends. It has the class name preceded by ~ and no parameters or return type. Most classes should rely on their member objects' destructors and do not need a custom destructor. This is the Rule of Zero: let standard members manage resources for you.

Class invariants

An invariant is a condition that should remain true for every valid object. For example, a bank account balance may be required to be non-negative. Constructors should establish the invariant, and public operations should preserve it.

Common mistakes

  • Writing a return type on a constructor.
  • Initializing members in the constructor body when an initializer list is needed.
  • Assuming members initialize in the order of the initializer list.
  • Adding a destructor that manually deletes resources already managed by vector, string, or smart pointers.

Practice

  1. Create a Rectangle class whose constructor initializes width and height.
  2. Reject invalid dimensions and decide how the constructor should report that error.
  3. Write a class with a vector member and explain why it does not need a custom destructor.
  4. Explain the difference between a constructor and a normal member function.

Practice solutions

Show worked solutions
  1. class Rectangle {
        double width;
        double height;
    public:
        Rectangle(double w, double h) : width(w), height(h) {}
    };
    The initializer list initializes both data members.
  2. For this example, reject non-positive dimensions by throwing std::invalid_argument. Include <stdexcept> and validate in the constructor body:
    #include <stdexcept>
    
    class Rectangle {
    public:
        Rectangle(double w, double h) : width(w), height(h) {
            if (width <= 0 || height <= 0) {
                throw std::invalid_argument("dimensions must be positive");
            }
        }
    
        double area() const noexcept {
            return width * height;
        }
    
    private:
        double width;
        double height;
    };
    If validation throws, the object is not successfully constructed.
  3. #include <vector>
    class Scores {
        std::vector<int> values;
    };
    The vector destroys its own elements and allocation. The containing class can use the compiler-generated destructor (Rule of Zero).
  4. A constructor initializes a new object and has no return type. An ordinary member function is called on an existing object and may return a value.

Check your understanding

In what order are members initialized?

Answer: In the order they are declared inside the class, regardless of the order in the initializer list.

Summary

Constructors establish valid initial state, initializer lists initialize members directly, and destructors end object lifetime and release owned resources. Prefer the Rule of Zero whenever standard members can manage resources for you.

References