Rule of Three in C++: What It Is and How It Works
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.
#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; }
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.