基本上是这样的:如果你不声明任何移动操作,你应该尊重三法则。如果您声明一个移动操作,那么“违反”三规则并没有什么坏处,因为编译器生成的操作的生成已经变得非常严格。即使您没有声明移动操作并违反了三规则,C++0x 编译器也会在用户声明一个特殊函数并且由于现已弃用“C++03 兼容性规则”。
我认为可以肯定地说这条规则变得不那么重要了。 C++03 中的真正问题是,实现不同的复制语义需要您用户声明 all 相关的特殊函数,以便它们都不是编译器生成的(否则会做错事)。但是 C++0x 改变了特殊成员函数生成的规则。如果用户仅声明其中一个函数来更改复制语义,它将阻止编译器自动生成剩余的特殊函数。这很好,因为缺少声明现在会将运行时错误变成编译错误(或至少是警告)。作为 C++03 兼容性措施,仍然会生成一些操作,但这一代已被视为已弃用,并且至少应在 C++0x 模式下产生警告。
由于编译器生成的特殊函数的限制性规则和 C++03 兼容性,三规则仍然是三规则。
以下是一些适用于最新 C++0x 规则的示例:
template<class T>
class unique_ptr
{
T* ptr;
public:
explicit unique_ptr(T* p=0) : ptr(p) {}
~unique_ptr();
unique_ptr(unique_ptr&&);
unique_ptr& operator=(unique_ptr&&);
};
在上面的示例中,不需要将任何其他特殊功能声明为已删除。由于限制性规则,它们根本不会生成。用户声明的移动操作的存在会禁用编译器生成的复制操作。但在这样的情况下:
template<class T>
class scoped_ptr
{
T* ptr;
public:
explicit scoped_ptr(T* p=0) : ptr(p) {}
~scoped_ptr();
};
现在预计 C++0x 编译器会针对可能由编译器生成的复制操作发出警告,这些操作可能会做错事。在这里,三件事的规则应该得到尊重。在这种情况下发出警告是完全合适的,它让用户有机会处理错误。我们可以通过删除函数来解决这个问题:
template<class T>
class scoped_ptr
{
T* ptr;
public:
explicit scoped_ptr(T* p=0) : ptr(p) {}
~scoped_ptr();
scoped_ptr(scoped_ptr const&) = delete;
scoped_ptr& operator=(scoped_ptr const&) = delete;
};
因此,仅仅因为 C++03 的兼容性,三规则在这里仍然适用。