0
0
CppConceptIntermediate · 3 min read

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

The Rule of Five in C++ states that if a class defines one of these special functions: destructor, copy constructor, copy assignment operator, move constructor, or move assignment operator, it should probably explicitly define all five. This ensures proper management of resources like memory and avoids bugs related to copying and moving objects.
⚙️

How It Works

Imagine you have a box that holds something valuable, like a toy or a gadget. When you want to make a copy of this box or move it somewhere else, you need to be careful to not lose or break what’s inside. In C++, classes that manage resources like memory or files need special care when copied or moved.

The Rule of Five tells you that if you write code to handle one of these special actions (destroying the box, copying it, or moving it), you should write code for all five actions to keep things safe and predictable. These five actions are: destructor (to clean up), copy constructor and copy assignment (to copy safely), and move constructor and move assignment (to move efficiently).

This rule helps prevent problems like double freeing memory or leaving resources unmanaged, which can cause crashes or leaks.

💻

Example

This example shows a simple class that manages a dynamic array and defines all five special functions following the Rule of Five.

cpp
class Array {
private:
    int* data;
    size_t size;

public:
    // Constructor
    Array(size_t s) : size(s), data(new int[s]) {}

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

    // Copy constructor
    Array(const Array& other) : size(other.size), data(new int[other.size]) {
        for (size_t i = 0; i < size; ++i) {
            data[i] = other.data[i];
        }
    }

    // Copy assignment operator
    Array& operator=(const Array& other) {
        if (this == &other) return *this;
        delete[] data;
        size = other.size;
        data = new int[size];
        for (size_t i = 0; i < size; ++i) {
            data[i] = other.data[i];
        }
        return *this;
    }

    // Move constructor
    Array(Array&& other) noexcept : size(other.size), data(other.data) {
        other.size = 0;
        other.data = nullptr;
    }

    // Move assignment operator
    Array& operator=(Array&& other) noexcept {
        if (this == &other) return *this;
        delete[] data;
        size = other.size;
        data = other.data;
        other.size = 0;
        other.data = nullptr;
        return *this;
    }
};
🎯

When to Use

Use the Rule of Five when your class manages resources that need explicit cleanup, like dynamic memory, file handles, or network connections. If your class owns such resources, you must carefully define how copying and moving happen to avoid errors like double deletion or resource leaks.

For example, if you write a class that holds a pointer to memory you allocate, you should implement all five special functions to control how that memory is copied, moved, and freed. This is common in classes that wrap raw pointers or system resources.

Key Points

  • The Rule of Five applies when your class manages resources manually.
  • Defining one special function usually means you need to define all five.
  • It prevents bugs related to copying and moving objects.
  • Modern C++ encourages using smart pointers to avoid manual Rule of Five management.

Key Takeaways

If you define one of destructor, copy/move constructor, or copy/move assignment, define all five.
The Rule of Five ensures safe copying and moving of resource-managing classes.
It helps avoid resource leaks and double frees in C++ programs.
Use smart pointers to reduce the need for manual Rule of Five implementations.