Rule of Three: If a class manages a resource (e.g., memory), then when explicitly implementing one of the following methods, the others should also be implemented:
C++11: Rule of Five – additional move operations were introduced:
Violating this rule can lead to resource ownership errors such as double deletion or memory leaks.
class Buffer { char* data; public: Buffer(size_t sz) : data(new char[sz]) {} ~Buffer() { delete[] data; } Buffer(const Buffer& other) : data(new char[strlen(other.data)+1]) { strcpy(data, other.data); } Buffer& operator=(const Buffer& other) { if (&other != this) { delete[] data; data = new char[strlen(other.data)+1]; strcpy(data, other.data); } return *this; } // move semantics in C++11+: Buffer(Buffer&& other) noexcept : data(other.data) { other.data = nullptr; } Buffer& operator=(Buffer&& other) noexcept { if (&other != this) { delete[] data; data = other.data; other.data = nullptr; } return *this; } };
Is it enough to implement only the destructor if the class manages a pointer?
No. Without copy and move operations, copying will result in double deletion of memory. For example:
Buffer a(10); Buffer b = a; // b and a will delete the same pointer!
Story
In the data aggregation platform for telecommunications, all classes wrote only the destructor. After refactoring, there was a mass failure due to double free: copying objects produced random behaviors.
Story
In the mobile game project, the move constructor was forgotten for the buffer container class. When moving, the object was copied, causing unnecessary data copying and performance drops.
Story
In the data serialization library, when returning an object from a function, a temporary object was returned, and the copy constructor made a shallow copy of the pointer. Many leaks arose that manifested only after months of operation.