Rule of five
- C++ course
- Intermediate
- Lesson 104/116
- 5 min
Learn the rule of five and resource management.
Rule of five
The rule of five says: if a class defines a destructor, copy constructor or copy assignment, it probably needs all five.
The five members are: ~T() (destructor), T(const T&) (copy constructor), T& operator=(const T&) (copy assignment), T(T&&) (move constructor) and T& operator=(T&&) (move assignment). If a class manages a resource (raw pointer, file handle) and you only define the destructor, copying does a shallow copy and causes a double-free error. That is why writing all five is the safest approach.
Rule of zero
In modern C++ the rule of zero is preferred: if a class holds only resource-managing members like std::string, std::vector or smart pointers, you do not need to define any special members.
The compiler automatically generates correct move and copy operations for those members. Example: class Student { std::string name; std::vector<int> grades; }; needs no special members and everything works automatically. With raw pointers you need the rule of five; with smart pointers the rule of zero suffices. That is why modern C++ avoids raw pointers.
Practice Add move members to the Buffer class
The Buffer class in the starting code already has a destructor, copy constructor and copy assignment (three of the rule of five). Add the move constructor and move assignment. In main move a into b with std::move and print b.data with std::cout.
Starter code
#include <iostream>
#include <string>
#include <utility>
class Buffer {
public:
std::string data;
Buffer(std::string d) : data(d) {}
~Buffer() {}
Buffer(const Buffer& other) : data(other.data) {}
Buffer& operator=(const Buffer& other) { data = other.data; return *this; }
// Add move constructor and move assignment
};
int main() {
Buffer a("Hello");
// Move a into b and print b.data
return 0;
}Sample solution
#include <iostream>
#include <string>
#include <utility>
class Buffer {
public:
std::string data;
Buffer(std::string d) : data(d) {}
~Buffer() {}
Buffer(const Buffer& other) : data(other.data) {}
Buffer& operator=(const Buffer& other) { data = other.data; return *this; }
Buffer(Buffer&& other) : data(std::move(other.data)) {}
Buffer& operator=(Buffer&& other) { data = std::move(other.data); return *this; }
};
int main() {
Buffer a("Hello");
Buffer b(std::move(a));
std::cout << b.data;
return 0;
}Expected output
Hello
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Match each of the five members to its role
| Term | Meaning |
|---|---|
~T() |
Destructor |
T(const T&) |
Copy constructor |
T(T&&) |
Move constructor |
T& operator=(T&&) |
Move assignment |
2 How many members does the rule of five cover?
~T(); T(const T&); T(T&&);
T& operator=(const T&); T& operator=(T&&);- Three
- Two
- Five Correct answer
- Seven
Explanation: The rule of five covers five members.
3 Destructor signature
~____() { /* release the resource */ }
~Buffer() { /* release the resource */ }
Explanation: The destructor is written as ~ClassName().