The “Rule of Five” in C++ refers to a guideline for implementing the five special member functions in a class when managing resources. These special member functions are:
- Destructor
- Copy constructor
- Move constructor
- Copy assignment operator
- Move assignment operator
The Rule of Five suggests that if you need to explicitly define or customize any of these special member functions, you should typically define or customize all five of them together to ensure proper resource management and prevent issues like resource leaks or double deletions.
Let’s look at an example to understand how the Rule of Five works:
#include <iostream>
class Resource {
private:
int* data;
int size;
public:
// Constructor
Resource(int s) : size(s) {
data = new int[size];
for (int i = 0; i < size; ++i) {
data[i] = i;
}
std::cout << "Resource constructed." << std::endl;
}
// Destructor
~Resource() {
delete[] data;
std::cout << "Resource destroyed." << std::endl;
}
// Copy constructor
Resource(const Resource& other) : size(other.size) {
data = new int[size];
for (int i = 0; i < size; ++i) {
data[i] = other.data[i];
}
std::cout << "Resource copied." << std::endl;
}
// Move constructor
Resource(Resource&& other) noexcept : data(other.data), size(other.size) {
other.data = nullptr;
other.size = 0;
std::cout << "Resource moved." << std::endl;
}
// Copy assignment operator
Resource& operator=(const Resource& other) {
if (this != &other) {
delete[] data;
size = other.size;
data = new int[size];
for (int i = 0; i < size; ++i) {
data[i] = other.data[i];
}
}
std::cout << "Resource copied (assignment)." << std::endl;
return *this;
}
// Move assignment operator
Resource& operator=(Resource&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data;
size = other.size;
other.data = nullptr;
other.size = 0;
}
std::cout << "Resource moved (assignment)." << std::endl;
return *this;
}
};
int main() {
Resource r1(5);
Resource r2(r1); // Copy constructor
Resource r3(std::move(r1)); // Move constructor
r1 = r2; // Copy assignment operator
r2 = std::move(r3); // Move assignment operator
return 0;
}
In this example, we have a Resource
class that manages a dynamically allocated array of integers. The constructor initializes the data
array, and the destructor releases the memory when the object is destroyed. The copy constructor, move constructor, copy assignment operator, and move assignment operator are also implemented.
In the main()
function, we create Resource
objects r1
, r2
, and r3
using different constructors and assignment operations. By implementing all five special member functions according to the Rule of Five, we ensure that resources are properly managed and transferred between objects. The output will show messages indicating the construction, copying, moving, and destruction of the Resource
objects.
It’s important to note that with C++11 and later, the Rule of Five is often replaced or supplemented by the Rule of Zero, which recommends relying on smart pointers and standard library containers to manage resources whenever possible, reducing the need for explicit resource management.