SyntaxStudy
Sign Up
C++ Constructors, Destructors, and the Rule of Three
C++ Beginner 1 min read

Constructors, Destructors, and the Rule of Three

A constructor is a special member function invoked when an object is created. C++ supports multiple constructors through overloading, including a default constructor (no parameters), parameterised constructors, and a copy constructor. The member initialiser list — the colon-separated list between the constructor signature and its body — is the preferred way to initialise data members, as it can be more efficient than assignment inside the body. The destructor is called when an object leaves scope or is explicitly deleted. Its primary purpose is to release resources acquired during the object's lifetime — file handles, heap memory, network connections, and so on. Destructors are identified by a tilde prefix ('~ClassName') and must not throw exceptions. The Rule of Three states that if a class defines any one of a destructor, copy constructor, or copy-assignment operator, it should almost certainly define all three. Classes that manage raw memory or other exclusive resources are the classic candidates. Modern C++11 extended this to the Rule of Five by adding the move constructor and move-assignment operator.
Example
#include <iostream>
#include <cstring>   // std::strlen, std::strcpy

class MyString {
public:
    // Parameterised constructor
    explicit MyString(const char* s = "") {
        len_  = std::strlen(s);
        data_ = new char[len_ + 1];
        std::strcpy(data_, s);
        std::cout << "Constructed: " << data_ << "\n";
    }

    // Copy constructor (deep copy)
    MyString(const MyString& other) {
        len_  = other.len_;
        data_ = new char[len_ + 1];
        std::strcpy(data_, other.data_);
        std::cout << "Copy-constructed: " << data_ << "\n";
    }

    // Copy-assignment operator
    MyString& operator=(const MyString& other) {
        if (this == &other) return *this;   // self-assignment guard
        delete[] data_;
        len_  = other.len_;
        data_ = new char[len_ + 1];
        std::strcpy(data_, other.data_);
        std::cout << "Assigned: " << data_ << "\n";
        return *this;
    }

    // Destructor — frees heap memory
    ~MyString() {
        std::cout << "Destroyed: " << data_ << "\n";
        delete[] data_;
    }

    const char* c_str() const { return data_; }

private:
    char*       data_;
    std::size_t len_;
};

int main() {
    MyString a("hello");
    MyString b = a;      // copy constructor
    MyString c("world");
    c = a;               // copy-assignment
    return 0;
}