五规则
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;
}
从三规则延伸到五规则对于性能原因很重要,但在大多数情况下并非绝对必要。添加复制构造函数和赋值运算符可确保移动类型不会泄漏内存(在这种情况下,移动构造将简单地回退到复制),但将执行调用者可能没有预料到的副本。