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


当前回答

我想说,三原则变成了三、四、五原则:

Each class should explicitly define exactly one of the following set of special member functions: None Destructor, copy constructor, copy assignment operator In addition, each class that explicitly defines a destructor may explicitly define a move constructor and/or a move assignment operator. Usually, one of the following sets of special member functions is sensible: None (for many simple classes where the implicitly generated special member functions are correct and fast) Destructor, copy constructor, copy assignment operator (in this case the class will not be movable) Destructor, move constructor, move assignment operator (in this case the class will not be copyable, useful for resource-managing classes where the underlying resource is not copyable) Destructor, copy constructor, copy assignment operator, move constructor (because of copy elision, there is no overhead if the copy assignment operator takes its argument by value) Destructor, copy constructor, copy assignment operator, move constructor, move assignment operator

注意:

That move constructor and move assignment operator won't be generated for a class that explicitly declares any of the other special member functions (like destructor or copy-constructor or move-assignment operator). That copy constructor and copy assignment operator won't be generated for a class that explicitly declares a move constructor or move assignment operator. And that a class with an explicitly declared destructor and implicitly defined copy constructor or implicitly defined copy assignment operator is considered deprecated.

特别是以下完全有效的c++ 03多态基类:

class C {
  virtual ~C() { }   // allow subtype polymorphism
};

应改写如下:

class C {
  C(const C&) = default;               // Copy constructor
  C(C&&) = default;                    // Move constructor
  C& operator=(const C&) = default;  // Copy assignment operator
  C& operator=(C&&) = default;       // Move assignment operator
  virtual ~C() { }                     // Destructor
};

这有点烦人,但可能比另一种方法更好(在这种情况下,自动生成只用于复制的特殊成员函数,没有移动的可能性)。

In contrast to the Rule of the Big Three, where failing to adhere to the rule can cause serious damage, not explicitly declaring the move constructor and move assignment operator is generally fine but often suboptimal with respect to efficiency. As mentioned above, move constructor and move assignment operators are only generated if there is no explicitly declared copy constructor, copy assignment operator or destructor. This is not symmetric to the traditional C++03 behavior with respect to auto-generation of copy constructor and copy assignment operator, but is much safer. So the possibility to define move constructors and move assignment operators is very useful and creates new possibilities (purely movable classes), but classes that adhere to the C++03 Rule of the Big Three will still be fine.

For resource-managing classes you can define the copy constructor and copy assignment operator as deleted (which counts as definition) if the underlying resource cannot be copied. Often you still want move constructor and move assignment operator. Copy and move assignment operators will often be implemented using swap, as in C++03. Talking about swap; if we already have a move-constructor and move-assignment operator, specializing std::swap will become unimportant, because the generic std::swap uses the move-constructor and move-assignment operator if available (and that should be fast enough).

不用于资源管理(即没有非空析构函数)或子类型多态性(即没有虚析构函数)的类不应该声明这五个特殊成员函数中的任何一个;它们都是自动生成的,行为正确且快速。

其他回答

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

我想说,三原则变成了三、四、五原则:

Each class should explicitly define exactly one of the following set of special member functions: None Destructor, copy constructor, copy assignment operator In addition, each class that explicitly defines a destructor may explicitly define a move constructor and/or a move assignment operator. Usually, one of the following sets of special member functions is sensible: None (for many simple classes where the implicitly generated special member functions are correct and fast) Destructor, copy constructor, copy assignment operator (in this case the class will not be movable) Destructor, move constructor, move assignment operator (in this case the class will not be copyable, useful for resource-managing classes where the underlying resource is not copyable) Destructor, copy constructor, copy assignment operator, move constructor (because of copy elision, there is no overhead if the copy assignment operator takes its argument by value) Destructor, copy constructor, copy assignment operator, move constructor, move assignment operator

注意:

That move constructor and move assignment operator won't be generated for a class that explicitly declares any of the other special member functions (like destructor or copy-constructor or move-assignment operator). That copy constructor and copy assignment operator won't be generated for a class that explicitly declares a move constructor or move assignment operator. And that a class with an explicitly declared destructor and implicitly defined copy constructor or implicitly defined copy assignment operator is considered deprecated.

特别是以下完全有效的c++ 03多态基类:

class C {
  virtual ~C() { }   // allow subtype polymorphism
};

应改写如下:

class C {
  C(const C&) = default;               // Copy constructor
  C(C&&) = default;                    // Move constructor
  C& operator=(const C&) = default;  // Copy assignment operator
  C& operator=(C&&) = default;       // Move assignment operator
  virtual ~C() { }                     // Destructor
};

这有点烦人,但可能比另一种方法更好(在这种情况下,自动生成只用于复制的特殊成员函数,没有移动的可能性)。

In contrast to the Rule of the Big Three, where failing to adhere to the rule can cause serious damage, not explicitly declaring the move constructor and move assignment operator is generally fine but often suboptimal with respect to efficiency. As mentioned above, move constructor and move assignment operators are only generated if there is no explicitly declared copy constructor, copy assignment operator or destructor. This is not symmetric to the traditional C++03 behavior with respect to auto-generation of copy constructor and copy assignment operator, but is much safer. So the possibility to define move constructors and move assignment operators is very useful and creates new possibilities (purely movable classes), but classes that adhere to the C++03 Rule of the Big Three will still be fine.

For resource-managing classes you can define the copy constructor and copy assignment operator as deleted (which counts as definition) if the underlying resource cannot be copied. Often you still want move constructor and move assignment operator. Copy and move assignment operators will often be implemented using swap, as in C++03. Talking about swap; if we already have a move-constructor and move-assignment operator, specializing std::swap will become unimportant, because the generic std::swap uses the move-constructor and move-assignment operator if available (and that should be fast enough).

不用于资源管理(即没有非空析构函数)或子类型多态性(即没有虚析构函数)的类不应该声明这五个特殊成员函数中的任何一个;它们都是自动生成的,行为正确且快速。