C++ 中的 "三規則 "和 "五規則 "是管理類中資源管理函數(特殊成員函數)的準則。這些規則有助于確保類正確一致地管理動態內存、文件句柄或網絡連接等資源。
The Rule of Three and the Rule of Five in C++ are guidelines for managing the resource management functions (special member functions) in a class. These rules help ensure that classes manage resources like dynamic memory, file handles, or network connections correctly and consistently.
Rule of Three
"三原則"指出,如果一個類定義了以下內容之一,那么它可能應該明確定義所有三項內容:
The Rule of Three states that if a class defines one of the following, it should probably explicitly define all three:
1, Destructor
2, Copy Constructor
3, Copy Assignment Operator
之所以會出現這條規則,是因為如果一個類管理一個資源(如動態內存),編譯器提供的這些函數的默認實現可能無法正確處理該資源,從而導致重復刪除或資源泄漏等問題。
This rule arises because if a class manages a resource (like dynamic memory), the default implementations of these functions provided by the compiler might not handle the resource correctly, leading to issues like double deletion or resource leaks.
Example:
#include <iostream>
class RuleOfThree {
private:
????int* data;
public:
????RuleOfThree(int value) : data(new int(value)) {}
????~RuleOfThree() {
????????delete data;
????}
????// Copy constructor
????RuleOfThree(const RuleOfThree& other) : data(new int(*other.data)) {}
? ? // Copy assignment operator
????RuleOfThree& operator=(const RuleOfThree& other) {
????????if (this == &other) {
????????????return *this;
????????}
????????delete data;
????????data = new int(*other.data);
????????return *this;
????}
};
Rule of Five
隨著 C++11 的推出,移動語義被添加到語言中,并由此產生了 "五法則"。五規則擴展了三規則,將移動操作也包括在內:
With the introduction of C++11, move semantics were added to the language, which led to the Rule of Five. The Rule of Five extends the Rule of Three to include move operations:
1, Destructor
2, Copy Constructor
3, Copy Assignment Operator
4, Move Constructor
5, Move Assignment Operator
對于管理資源的類來說,移動操作是必要的,因為它可以從臨時對象中有效地轉移資源,避免不必要的深度拷貝。
Move operations are necessary for classes that manage resources because they allow efficient transfer of resources from temporary objects, avoiding unnecessary deep copies.
Example:
#include <iostream>
class RuleOfFive {
private:
????int* data;
public:
????RuleOfFive(int value) : data(new int(value)) {}
????~RuleOfFive() {
????????delete data;
????}
????// Copy constructor
????RuleOfFive(const RuleOfFive& other) : data(new int(*other.data)) {}
????// Copy assignment operator
????RuleOfFive& operator=(const RuleOfFive& other) {
????????if (this == &other) {
????????????return *this;
????????}
????????delete data;
????????data = new int(*other.data);
????????return *this;
????}
????// Move constructor
????RuleOfFive(RuleOfFive&& other) noexcept : data(other.data) {
????????other.data = nullptr;
????}
????// Move assignment operator
????RuleOfFive& operator=(RuleOfFive&& other) noexcept {
????????if (this == &other) {
????????????return *this;
????????}
????????delete data;
????????data = other.data;
????????other.data = nullptr;
????????return *this;
????}
};
Summary
-
三原則: 如果你定義了析構函數、復制構造函數或復制賦值操作符中的任何一種,你可能應該定義所有三種。
-
五條規則: 在 C++11 中增加了移動語義后,如果您定義了析構函數、復制構造函數、復制賦值操作符、移動構造函數或移動賦值操作符中的任何一種,則應定義所有五種。
這些規則有助于確保您的類正確管理其資源,避免資源泄露、重復刪除和低效深度拷貝等問題。
-
Rule of Three: If you define any of the destructor, copy constructor, or copy assignment operator, you should probably define all three.
-
Rule of Five: With the addition of move semantics in C++11, if you define any of the destructor, copy constructor, copy assignment operator, move constructor, or move assignment operator, you should define all five.
These rules help ensure that your class correctly manages its resources, avoiding issues like resource leaks, double deletions, and inefficient deep copies.