1. Vấn đề nó giải quyết
Rule of Five hoàn chỉnh ngữ nghĩa sở hữu thủ công; Rule of Zero giao sở hữu cho member RAII; noexcept báo rằng thao tác move không ném exception. Nó làm ràng buộc quan trọng hiện rõ thay vì bắt người đọc đoán. Bài chỉ giữ phần cốt lõi C++11 vừa đủ cho một ngày tập trung.
2. Kiến thức cần có
Kiến thức Ngày 19, cùng biến, hàm và cách đọc output đã học trước đó.
3. Ý tưởng cốt lõi
Mental model: Rule of Five hoàn chỉnh ngữ nghĩa sở hữu thủ công; Rule of Zero giao sở hữu cho member RAII; noexcept báo rằng thao tác move không ném exception. Hãy xác định giá trị hoặc trạng thái liên quan, ai sở hữu nó và quy tắc tác động lúc compile hay lúc chạy.
4. Cú pháp tối thiểu
Owner(Owner&& other) noexcept; Owner& operator=(Owner&& other) noexcept;5. Cách nó hoạt động
Ví dụ tạo dữ liệu nhỏ, cố định và không cần nhập bàn phím.
C++11 hoặc contract thư viện chuẩn áp dụng quy tắc hôm nay.
Chương trình in kết quả quan trọng để đối chiếu với mã nguồn.
6. Lỗi thường gặp
Khai báo move là
noexceptkhi nó vẫn có thể ném sẽ gọistd::terminate; bỏ bảo đảm thật có thể khiến container phải copy.
7. Khi nào nên dùng
Nên dùng khi xem xét kiểu sở hữu, đồng thời ưu tiên Rule of Zero cho code mới.
Tránh dùng khi nó che ownership, lifetime, kiểu, thứ tự hoặc chi phí.
8. Ví dụ đơn giản
Kiểu sở hữu thủ công định nghĩa đủ năm special operation với move không ném; kiểu chỉ chứa string không cần tự định nghĩa hàm nào. File .cpp dùng dữ liệu cố định và không thêm abstraction ngoài chủ đề.
Mã mẫu hoàn chỉnh
Tệp mã nguồn
cpp11/20_rule_of_five_zero_noexcept_move/main.cpp
#include <iostream>
#include <string>
#include <utility>
class Owner {
public:
explicit Owner(int value = 0) : data_(new int(value)) {}
~Owner() { delete data_; }
Owner(const Owner& other) : data_(new int(*other.data_)) {}
Owner& operator=(const Owner& other) {
if (this != &other) {
*data_ = *other.data_;
}
return *this;
}
Owner(Owner&& other) noexcept : data_(other.data_) {
other.data_ = nullptr;
}
Owner& operator=(Owner&& other) noexcept {
if (this != &other) {
delete data_;
data_ = other.data_;
other.data_ = nullptr;
}
return *this;
}
int get() const { return data_ ? *data_ : -1; }
private:
int* data_;
};
struct RuleOfZero {
std::string label; // string manages its own resource
};
int main() {
Owner first(5);
Owner second(std::move(first));
RuleOfZero zero{"automatic"};
std::cout << second.get() << ' ' << zero.label << '\n';
}
9. Điều cần nhớ
Tính năng nằm trong phạm vi C++11 của lộ trình này.
Hiểu hệ quả về lifetime, ownership, kiểu và thứ tự trước khi dùng.
Compile với cảnh báo và ưu tiên cách viết nhỏ nhất làm quy tắc hiện rõ.
10. Câu hỏi tự kiểm tra
Dễ — Rule of Five và Rule of Zero khác nhau thế nào trong quản lý tài nguyên?
noexcepttrên move constructor cam kết điều gì?Trung bình — Đọc ví dụ nhỏ ở trên. Chương trình sẽ in giá trị hoặc trạng thái nào, và quy tắc nào tạo ra kết quả đó?
Khó — Tìm và giải thích lỗi tinh tế trong tình huống sau: Khai báo move là
noexceptkhi nó vẫn có thể ném sẽ gọistd::terminate; bỏ bảo đảm thật có thể khiến container phải copy. Cách sửa nhỏ nhất nhưng an toàn trong C++11 là gì?