0
0
CppConceptBeginner · 4 min read

Rule of Three in C++: What It Is and How It Works

The Rule of Three in C++ states that if a class defines one of these: a destructor, a copy constructor, or a copy assignment operator, it should probably define all three. This rule helps manage resources like memory safely to avoid bugs like double deletion or memory leaks.
⚙️

How It Works

Imagine you have a class that manages a resource, like memory or a file handle. When you copy or assign objects of this class, you need to make sure the resource is handled correctly to avoid problems like freeing the same memory twice or losing track of it.

The Rule of Three says that if you write a custom destructor to clean up resources, you also need to write a copy constructor and a copy assignment operator. This is because the default versions provided by C++ just copy the pointers, not the actual resource, which can cause errors.

Think of it like lending a book: if you only write instructions on how to return the book (destructor), but not how to make a copy of the book (copy constructor) or swap books (copy assignment), you might end up with two people thinking they own the same book, causing confusion.

💻

Example

This example shows a class that manages a dynamic array. It defines all three special functions to safely copy and clean up the array.

cpp
#include <iostream>
#include <cstring>

class MyString {
private:
    char* data;
public:
    // Constructor
    MyString(const char* str = "") {
        data = new char[std::strlen(str) + 1];
        std::strcpy(data, str);
    }

    // Destructor
    ~MyString() {
        delete[] data;
    }

    // Copy constructor
    MyString(const MyString& other) {
        data = new char[std::strlen(other.data) + 1];
        std::strcpy(data, other.data);
    }

    // Copy assignment operator
    MyString& operator=(const MyString& other) {
        if (this != &other) {
            delete[] data;
            data = new char[std::strlen(other.data) + 1];
            std::strcpy(data, other.data);
        }
        return *this;
    }

    void print() const {
        std::cout << data << std::endl;
    }
};

int main() {
    MyString a("Hello");
    MyString b = a; // Calls copy constructor
    MyString c;
    c = b; // Calls copy assignment

    a.print();
    b.print();
    c.print();

    return 0;
}
Output
Hello Hello Hello
🎯

When to Use

Use the Rule of Three when your class manages resources that need explicit cleanup, like dynamic memory, file handles, or network connections. If you only rely on the default copy and assignment, you risk shallow copies that can cause crashes or leaks.

For example, if you write a class that allocates memory with new, you should define all three: destructor to free memory, copy constructor to make a deep copy, and copy assignment operator to replace existing data safely.

Modern C++ often uses smart pointers or other tools to avoid manual resource management, but understanding the Rule of Three helps you write safe and correct code when manual control is needed.

Key Points

  • If you define one of destructor, copy constructor, or copy assignment operator, define all three.
  • Helps prevent resource management bugs like double deletion or memory leaks.
  • Default copy operations do shallow copies, which can be unsafe for resources.
  • Modern C++ uses Rule of Five or smart pointers, but Rule of Three is foundational.

Key Takeaways

Always define destructor, copy constructor, and copy assignment operator together when managing resources.
Default copy operations do shallow copies that can cause bugs with resource management.
The Rule of Three helps avoid crashes and memory leaks in classes with manual resource control.
Modern C++ alternatives exist, but understanding Rule of Three is essential for safe code.
Use this rule when your class owns raw pointers or other resources needing explicit cleanup.