Rule of Three (C++03): nếu class cần tự định nghĩa một trong ba thứ, thì thường cần cả ba:
1. Destructor
2. Copy constructor
3. Copy assignment operator
Rule of Five (C++11): thêm 2 từ move semantics:
4. Move constructor
5. Move assignment operator
Nguyên nhân: khi class tự quản lý tài nguyên raw (pointer, file handle...), compiler-generated defaults làm shallow copy → double-free hoặc memory leak.
class Buffer {
int* data_; size_t size_;
public:
Buffer(size_t n) : size_(n), data_(new int[n]) {}
~Buffer() { delete[] data_; }
// Copy — deep copy
Buffer(const Buffer& o) : size_(o.size_), data_(new int[o.size_]) {
std::copy(o.data_, o.data_ + size_, data_);
}
Buffer& operator=(const Buffer& o) {
if (this != &o) { delete[] data_; size_ = o.size_; data_ = new int[size_];
std::copy(o.data_, o.data_ + size_, data_); }
return *this;
}
// Move — steal resources
Buffer(Buffer&& o) noexcept : size_(o.size_), data_(o.data_) {
o.data_ = nullptr; o.size_ = 0;
}
Buffer& operator=(Buffer&& o) noexcept {
if (this != &o) { delete[] data_; data_ = o.data_; size_ = o.size_;
o.data_ = nullptr; o.size_ = 0; }
return *this;
}
};Rule of Zero (tốt nhất): dùng smart pointer + STL containers → compiler tự gen đủ 5 hàm đặc biệt, không cần tự viết.
Rule of Three (C++03): if a class needs to define any one of these three, it likely needs all three:
1. Destructor
2. Copy constructor
3. Copy assignment operator
Rule of Five (C++11): adds two more from move semantics:
4. Move constructor
5. Move assignment operator
Why: when a class manages a raw resource (pointer, file handle...), compiler-generated defaults do shallow copy → double-free or memory leak.
class Buffer {
int* data_; size_t size_;
public:
Buffer(size_t n) : size_(n), data_(new int[n]) {}
~Buffer() { delete[] data_; }
// Copy — deep copy
Buffer(const Buffer& o) : size_(o.size_), data_(new int[o.size_]) {
std::copy(o.data_, o.data_ + size_, data_);
}
Buffer& operator=(const Buffer& o) {
if (this != &o) { delete[] data_; size_ = o.size_; data_ = new int[size_];
std::copy(o.data_, o.data_ + size_, data_); }
return *this;
}
// Move — steal resources
Buffer(Buffer&& o) noexcept : size_(o.size_), data_(o.data_) {
o.data_ = nullptr; o.size_ = 0;
}
Buffer& operator=(Buffer&& o) noexcept {
if (this != &o) { delete[] data_; data_ = o.data_; size_ = o.size_;
o.data_ = nullptr; o.size_ = 0; }
return *this;
}
};Rule of Zero (preferred): use smart pointers + STL containers so the compiler generates all five special members automatically.