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


当前回答

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的兼容性,三原则在这里仍然适用。

其他回答

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的兼容性,三原则在这里仍然适用。

是的,我认为为这样的类提供一个移动构造函数会很好,但请记住:

It's only an optimization. Implementing only one or two of the copy constructor, assignment operator or destructor will probably lead to bugs, while not having a move constructor will just potentially reduce performance. Move constructor cannot always be applied without modifications. Some classes always have their pointers allocated, and thus such classes always delete their pointers in the destructor. In these cases you'll need to add extra checks to say whether their pointers are allocated or have been moved away (are now null).

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

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

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

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

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

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

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

在一般情况下,是的,三的规则变成了五的规则,添加了move赋值操作符和move构造函数。然而,并不是所有的类都是可复制和可移动的,有些只是可移动的,有些只是可复制的。

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

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

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