五規則

Version >= C++ 11

C++ 11 引入了兩個新的特殊成員函式:移動建構函式和移動賦值運算子。由於你想要遵循 C++ 03 中的 Rule of Three 的所有相同的原因,你通常想要遵循 C++ 11 中的 Five of Rule:如果一個類需要五個特殊成員函式中的一個,並且如果移動語義如果需要,那麼它很可能需要五個。

但是,請注意,未遵循五法則通常不會被視為錯誤,而是錯過優化機會,只要仍然遵循三法則。如果編譯器通常不使用移動建構函式或移動賦值運算子,則它將在可能的情況下使用複製語義,從而導致由於不必要的複製操作而導致操作效率降低。如果類不需要移動語義,則不需要宣告移動建構函式或賦值運算子。

與三規則相同的例子:

class Person
{
    char* name;
    int age;

public:
    // Destructor 
    ~Person() { delete [] name; }

    // Implement Copy Semantics
    Person(Person const& other)
        : name(new char[std::strlen(other.name) + 1])
        , age(other.age)
    {
        std::strcpy(name, other.name);
    }
    
    Person &operator=(Person const& other) 
    {
        // Use copy and swap idiom to implement assignment.
        Person copy(other);
        swap(*this, copy);
        return *this;
    }

    // Implement Move Semantics
    // Note: It is usually best to mark move operators as noexcept
    //       This allows certain optimizations in the standard library
    //       when the class is used in a container.

    Person(Person&& that) noexcept
        : name(nullptr)               // Set the state so we know it is undefined
        , age(0)
    {
        swap(*this, that);
    }

    Person& operator=(Person&& that) noexcept
    {
        swap(*this, that);
        return *this;
    }

    friend void swap(Person& lhs, Person& rhs) noexcept
    {
        std::swap(lhs.name, rhs.name);
        std::swap(lhs.age, rhs.age);
    }
};

或者,複製和移動賦值運算子都可以用單個賦值運算子替換,它通過值而不是引用或右值引用來獲取例項,以便於使用複製和交換習慣用法。

Person& operator=(Person copy)
{
    swap(*this, copy);
    return *this;
}

三規則延伸到五規則對於效能原因很重要,但在大多數情況下並非絕對必要。新增複製建構函式和賦值運算子可確保移動型別不會洩漏記憶體(在這種情況下,移動構造將簡單地回退到複製),但將執行呼叫者可能沒有預料到的副本。