Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C++

Quy tắc Ba (Rule of Three) trong C++


Quy tắc Ba: Nếu một class cần định nghĩa rõ ràng **một trong ba** hàm sau, thường thì nó cần định nghĩa **cả ba**:

  1. Copy Constructor - Class(const Class&)
  2. Copy Assignment Operator - Class& operator=(const Class&)
  3. Destructor - ~Class()

Tại sao?

Class quản lý tài nguyên động (con trỏ, file handle, socket...). Bản sao mặc định (shallow copy) chỉ copy giá trị con trỏ → hai đối tượng cùng trỏ một vùng nhớ → double free, memory leak, dữ liệu sai.

Ví dụ vi phạm Rule of Three

class Bad {
    int* data;
public:
    Bad(int sz) : data(new int[sz]) {}
    // Thiếu: copy ctor, assignment, dtor
};
int main() {
    Bad a(10);
    Bad b = a; // Shallow copy: cả hai trỏ cùng mảng
} // Double free khi a và b hủy

Ví dụ tuân thủ Rule of Three (C++98)

class Good {
    int* data; size_t sz;
public:
    Good(size_t n) : sz(n), data(new int[n]) {}
    ~Good() { delete[] data; }
    // Copy constructor - Deep copy
    Good(const Good& other) : sz(other.sz), data(new int[other.sz]) {
        copy(other.data, other.data+sz, data);
    }
    // Copy assignment - Copy-and-swap idiom
    Good& operator=(Good other) { // pass by value -> copy
        swap(sz, other.sz);
        swap(data, other.data);
        return *this;
    } // other hủy, giải phóng data cũ
};

C++11: Rule of Five

Thêm **Move Constructor** và **Move Assignment** để tối ưu hiệu năng:

Good(Good&& other) noexcept : data(other.data), sz(other.sz) {
    other.data = nullptr; other.sz = 0;
}
Good& operator=(Good&& other) noexcept {
    delete[] data;
    data = other.data; sz = other.sz;
    other.data = nullptr; other.sz = 0;
    return *this;
}

C++11/14/17: Rule of Zero (Khuyên dùng)

Sử dụng RAII containers (vector, unique_ptr, shared_ptr) để **không cần viết** bất kỳ hàm nào trong Rule of Three/Five. Compiler-generated sẽ đúng.

class Modern {
    vector<int> data; // Tự quản lý bộ nhớ
public:
    Modern(size_t n) : data(n) {}
    // Không cần dtor, copy, move - compiler làm đúng!
};