所以,在看了这个关于右值引用的精彩讲座后,我认为每个类都将受益于这样一个“移动构造函数”,模板<类T> MyClass(t&&other)编辑,当然还有一个“移动赋值操作符”,模板<类T> MyClass& operator=(t&&other),菲利普在他的回答中指出,如果它有动态分配的成员,或者通常存储指针。就像你应该有一个复制函数,赋值操作符和析构函数,如果前面提到的点适用。 想法吗?


当前回答

我们现在不能说规则3变成了规则4(或规则5),而不破坏所有执行规则3的现有代码,也不实现任何形式的移动语义。

3规则的意思是,如果你实现了一个,你就必须实现所有3个。

也不知道会有任何自动生成的移动。“规则3”的目的是因为它们自动存在,如果你实现了其中一个,那么其他两个的默认实现很可能是错误的。

其他回答

Basically, it's like this: If you don't declare any move operations, you should respect the rule of three. If you declare a move operation, there is no harm in "violating" the rule of three as the generation of compiler-generated operations has gotten very restrictive. Even if you don't declare move operations and violate the rule of three, a C++0x compiler is expected to give you a warning in case one special function was user-declared and other special functions have been auto-generated due to a now deprecated "C++03 compatibility rule".

I think it's safe to say that this rule becomes a little less significant. The real problem in C++03 is that implementing different copy semantics required you to user-declare all related special functions so that none of them is compiler-generated (which would otherwise do the wrong thing). But C++0x changes the rules about special member function generation. If the user declares just one of these functions to change the copy semantics it'll prevent the compiler from auto-generating the remaining special functions. This is good because a missing declaration turns a runtime error into a compilation error now (or at least a warning). As a C++03 compatibility measure some operations are still generated but this generation is deemed deprecated and should at least produce a warning in C++0x mode.

由于编译器生成的特殊函数的限制规则和c++ 03的兼容性,3的规则仍然是3的规则。

下面是一些适用于最新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的兼容性,三原则在这里仍然适用。

以下是自2011年1月24日以来的当前状态和相关发展的简短更新。

根据c++ 11标准(见附件D的[depr.impldec]):

如果类具有用户声明的复制赋值操作符或用户声明的析构函数,则不建议使用复制构造函数的隐式声明。如果类具有用户声明的复制构造函数或用户声明的析构函数,则不建议使用复制赋值操作符的隐式声明。

它实际上是被提议废弃的行为,给c++ 14一个真正的“五规则”而不是传统的“三规则”。2013年,EWG投票反对在2014年c++中实现这一提议。对该提案做出决定的主要理由与对破坏现有代码的普遍担忧有关。

最近,又有人提议对c++ 11的措辞进行调整,以实现非正式的五规则,即

如果这些函数是用户提供的,则编译器不能生成复制函数、移动函数或析构函数。

如果被EWG批准,这个“规则”很可能被c++ 17采用。

真不敢相信没人跟这事有关。

文章基本上主张“零规则”。 我不适合引用整篇文章,但我认为这是主要观点:

具有自定义析构函数、复制/移动构造函数或复制/移动赋值操作符的类应该专门处理所有权。 其他类不应该有自定义析构函数、复制/移动 构造函数或复制/移动赋值操作符。

在我看来,这一点很重要:

标准中包括常见的“包中的所有权”类 库:std::unique_ptr和std::shared_ptr。通过使用 自定义删除器对象,两者都已变得足够灵活,可以进行管理 几乎任何种类的资源。

我不这么认为,“三原则”是一种经验法则,它指出实现了以下其中一项而不是全部的类可能是有bug的。

拷贝构造函数 赋值运算符 析构函数

然而,省略move构造函数或move赋值操作符并不意味着存在错误。这可能是在优化时错过了一个机会(在大多数情况下),或者移动语义与这个类不相关,但这不是一个错误。

虽然在相关的情况下定义一个move构造函数可能是最佳实践,但它不是强制性的。在很多情况下,移动构造函数与类无关(例如std::complex),所有在c++ 03中行为正确的类即使没有定义移动构造函数,也会在c++ 0x中继续正确地行为。

我们现在不能说规则3变成了规则4(或规则5),而不破坏所有执行规则3的现有代码,也不实现任何形式的移动语义。

3规则的意思是,如果你实现了一个,你就必须实现所有3个。

也不知道会有任何自动生成的移动。“规则3”的目的是因为它们自动存在,如果你实现了其中一个,那么其他两个的默认实现很可能是错误的。