簡體   English   中英

什么是四規則(半規則)?

[英]What is the Rule of Four (and a half)?

為了正確處理 object 復制,經驗法則是三法則 對於 C++11,移動語義是一回事,所以它是五法則 但是,在這里和互聯網上的討論中,我還看到了對四規則(半)的引用,它是五規則和復制和交換習語的組合。

那么究竟什么是四法則(半法則)? 需要實現哪些功能,每個功能的主體應該是什么樣的? 哪個function是一半? 與五法則相比,這種方法有什么缺點或警告嗎?

這是一個類似於我當前代碼的參考實現。 如果這是不正確的,正確的實現會是什么樣子?

//I understand that in this example, I could just use `std::unique_ptr`.
//Just assume it's a more complex resource.
#include <utility>

class Foo {
public:
    //We must have a default constructor so we can swap during copy construction.
    //It need not be useful, but it should be swappable and deconstructable.
    //It can be private, if it's not truly a valid state for the object.
    Foo() : resource(nullptr) {}

    //Normal constructor, acquire resource
    Foo(int value) : resource(new int(value)) {}

    //Copy constructor
    Foo(Foo const& other) {
        //Copy the resource here.
        resource = new int(*other.resource);
    }

    //Move constructor
    //Delegates to default constructor to put us in safe state.
    Foo(Foo&& other) : Foo() {
        swap(other);
    }

    //Assignment
    Foo& operator=(Foo other) {
        swap(other);
        return *this;
    }

    //Destructor
    ~Foo() {
        //Free the resource here.
        //We must handle the default state that can appear from the copy ctor.
        //(The if is not technically needed here. `delete nullptr` is safe.)
        if (resource != nullptr) delete resource;
    }

    //Swap
    void swap(Foo& other) {
        using std::swap;

        //Swap the resource between instances here.
        swap(resource, other.resource);
    }

    //Swap for ADL
    friend void swap(Foo& left, Foo& right) {
        left.swap(right);
    }

private:
    int* resource;
};

那么四分之一(一半)究竟是什么呢?

“四大(一半)規則”指出,如果你實施其中一個

  • 復制構造函數
  • 賦值運算符
  • 移動構造函數
  • 析構函數
  • 交換功能

那么你必須有一個關於其他人的政策。

需要實現哪些功能,每個功能的主體應該是什么樣的?

  • 默認構造函數(可以是私有的)
  • 復制構造函數(這里有真正的代碼來處理你的資源)
  • 移動構造函數(使用默認構造函數和交換):

     S(S&& s) : S{} { swap(*this, s); } 
  • 賦值運算符(使用構造函數和交換)

     S& operator=(S s) { swap(*this, s); } 
  • 析構函數(資源的深層副本)

  • friend swap(沒有默認實現:/你應該想要交換每個成員)。 這一點與swap成員方法相反: std::swap使用move(或copy)構造函數,這將導致無限遞歸。

一半的功能是什么?

從上一篇文章:

“為了實現Copy-Swap習慣用法,你的資源管理類還必須實現一個swap()函數來執行逐個成員的交換(這是你的”......(和一半)“)

所以swap方法。

與五法則相比,這種方法有任何缺點或警告嗎?

我已經寫過的警告是要編寫正確的交換以避免無限遞歸。

與五法則相比,這種方法有任何缺點或警告嗎?

雖然它可以節省代碼重復,但使用復制和交換只會導致更糟糕的類,更直接。 你正在傷害你的班級表現,包括移動任務(如果你使用統一分配操作員,我也不是它的粉絲),這應該非常快。 作為交換,您將獲得強大的異常保證,這在一開始看起來不錯。 問題是,您可以通過簡單的通用函數從任何類中獲得強大的異常保證:

template <class T>
void copy_and_swap(T& target, T source) {
    using std::swap;
    swap(target, std::move(source));
}

就是這樣。 因此,需要強大異常安全的人無論如何都可以獲得它。 坦率地說,強大的異常安全無論如何都是一個利基市場。

保存代碼重復的真正方法是通過Zero of Zero:選擇成員變量,這樣就不需要編寫任何特殊功能。 在現實生活中,我會說90%以上的時間我看到特殊的會員功能,他們可以很容易地避免。 即使你的類確實有某種一個特殊的成員函數需要特殊的邏輯,你通常是關閉向下推到一個成員更好。 您的記錄器類可能需要在其析構函數中刷新緩沖區,但這不是編寫析構函數的理由:編寫一個處理刷新的小緩沖區類,並將其作為記錄器的成員。 記錄器可能具有可以自動處理的各種其他資源,並且您希望讓編譯器自動生成復制/移動/破壞代碼。

關於C ++的事情是每個函數自動生成特殊函數是全部或全部。 這就是拷貝構造函數(如)要么被自動生成的,同時考慮到所有成員,或者你必須手工編寫(更糟的是,維持)這一切 所以它強烈推動你采取一種向下推動事物的方法。

如果您正在編寫一個類來管理資源並需要處理它,通常應該是:a)相對較小,b)相對通用/可重用。 前者意味着一些重復的代碼並不是什么大問題,而后者意味着您可能不希望將性能留在桌面上。

總而言之,我強烈反對使用復制和交換,以及使用統一賦值運算符。 嘗試遵循零規則,如果你不能,遵循五法則。 只有當你可以使它比通用交換(執行3次移動)更快時才寫swap ,但通常你不需要打擾。

簡單來說,只要記住這一點。

0 規則

Classes have neither custom destructors, copy/move constructors or copy/move assignment operators.

規則 3 :如果您實現了其中任何一個的自定義版本,那么您就實現了所有這些。

Destructor, Copy constructor, copy assignment

5 規則:如果您實現自定義移動構造函數或移動賦值運算符,則需要定義所有 5 個。 需要移動語義。

Destructor, Copy constructor, copy assignment, move constructor, move assignment

四個半規則:與規則 5 相同,但具有復制和交換習語。 通過包含交換方法,復制賦值和移動賦值合並為一個賦值運算符。

Destructor, Copy constructor, move constructor, assignment, swap (the half part)

Destructor: ~Class();
Copy constructor: Class(Class &);
Move constructor: Class(Class &&);
Assignment: Class & operator = (Class);
Swap: void swap(Class &);

沒有警告,優點是分配速度更快,因為按值復制實際上比在方法主體中創建臨時 object 更有效。

現在我們有了臨時 object,我們只需對臨時 object 執行交換。 當它超出 scope 時,它會自動銷毀,現在我們在 object 中擁有運算符右側的值。

參考資料

https://www.linkedin.com/learning/c-plus-plus-advanced-topics/rule-of-five?u=67551194 https://en.cppreference.com/w/cpp/language/rule_of_three

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM