template<class T> MyClass(T&& other)
template<class T> MyClass& operator=(T&& other)
是的,我认为为这样的类提供一个移动构造函数会很好,但请记住:
只实现一个或两个复制构造函数、赋值操作符或析构函数可能会导致错误,而没有移动构造函数只会潜在地降低性能。
如果没有修改,移动构造函数不能总是应用。
有些类总是分配它们的指针,因此这些类总是在析构函数中删除它们的指针。在这些情况下,你需要添加额外的检查,说他们的指针是否已分配或已移动(现在是空的)。
我们现在不能说规则3变成了规则4(或规则5),而不破坏所有执行规则3的现有代码,也不实现任何形式的移动语义。
3规则的意思是,如果你实现了一个,你就必须实现所有3个。
也不知道会有任何自动生成的移动。“规则3”的目的是因为它们自动存在,如果你实现了其中一个,那么其他两个的默认实现很可能是错误的。
我想说,三原则变成了三、四、五原则:
每个类应该明确定义一个 以下集合的特殊成员 功能:< / p > 没有一个 析构函数,复制构造函数,复制赋值操作符 此外,每个显式定义析构函数的类都可以显式定义move构造函数和/或move赋值操作符。 通常是下列特殊成员集之一 函数是敏感的: 无(对于许多隐式生成的特殊成员函数正确且快速的简单类) 析构函数,复制构造函数,复制赋值运算符(在本例中为 类将不会移动) 析构函数、移动构造函数、移动赋值操作符(在这种情况下,类将不可复制,对于底层资源不可复制的资源管理类很有用) 析构函数、复制构造函数、复制赋值操作符、移动构造函数(由于复制省略,如果复制赋值操作符按值接受其参数,则没有开销) 析构函数,复制构造函数,复制赋值操作符,移动构造函数 移动赋值操作符
此外,每个显式定义析构函数的类都可以显式定义move构造函数和/或move赋值操作符。
通常是下列特殊成员集之一 函数是敏感的:
注意:
特别是以下完全有效的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 };
有点烦人,但可能比另一种方法更好(在这种情况下,自动生成用于复制只有的特殊成员函数,没有移动的可能性)。
与三巨头规则相反,不遵守规则可能会造成严重的损害,不显式地声明move构造函数和move赋值操作符通常是可以的,但就效率而言往往不是最优的。如上所述,只有在没有显式声明复制构造函数、复制赋值操作符或析构函数时,才会生成移动构造函数和移动赋值操作符。这与传统c++ 03在自动生成复制构造函数和复制赋值操作符方面的行为不对称,但要安全得多。因此,定义move构造函数和move赋值操作符的可能性非常有用,并创建了新的可能性(纯可移动类),但坚持c++ 03三大规则的类仍然是可以的。
对于资源管理类,如果底层资源不能复制,则可以将复制构造函数和复制赋值操作符定义为deleted(这算作定义)。通常你还是需要move构造函数和move赋值操作符。复制和移动赋值操作符将经常使用swap实现,就像在c++ 03中一样。谈论swap;如果我们已经有了移动构造函数和移动赋值操作符,专业std::swap将变成不重要的,因为泛型std::swap在可用的情况下使用了移动构造函数和移动赋值操作符(这应该足够快)。
swap
std::swap
不用于资源管理(即没有非空析构函数)或子类型多态性(即没有虚析构函数)的类不应该声明这五个特殊成员函数中的任何一个;它们都是自动生成的,行为正确且快速。
在一般情况下,是的,三的规则变成了五的规则,添加了move赋值操作符和move构造函数。然而,不是所有类是可复制和可移动的,有些只是可移动的,有些只是可复制的。
我不这么认为,三的法则是一个经验法则,它指出一个类实现了以下其中之一,但不是全部,可能是有bug的。
然而,省略move构造函数或move赋值操作符并不意味着存在错误。它五月是一个错过的优化机会(在大多数情况下)或移动语义与这个类不相关,但这不是一个bug。
虽然在相关的情况下定义一个move构造函数可能是最佳实践,但它不是强制性的。在许多情况下,移动构造函数与类无关(例如std::complex),并且所有在c++ 03中行为正确的类即使没有定义移动构造函数,也将在c++ 0x中继续正确地行为。
std::complex
基本上,它是这样的:如果你没有声明任何移动操作,你应该尊重规则三。如果声明一个move操作,“违反”3规则也没有什么害处,因为编译器生成的操作的生成已经变得非常受限。即使你没有声明move操作,并且违反了规则三,c++ 0x编译器也会给你一个警告,如果一个特殊函数是用户声明的,而其他特殊函数由于“c++ 03兼容性规则”而自动生成。
我认为可以肯定地说,这条规则变得不那么重要了。c++ 03中真正的问题是,实现不同的复制语义需要用户声明与所有相关的特殊函数,这样它们就不会是编译器生成的(否则会做错误的事情)。但是c++ 0x改变了关于特殊成员函数生成的规则。如果用户只声明了其中一个函数来改变复制语义,则会阻止编译器自动生成其余的特殊函数。这很好,因为缺失的声明现在会将运行时错误转换为编译错误(或者至少是警告)。作为c++ 03兼容性度量,仍然会生成一些操作,但该生成被认为已弃用,至少应该在c++ 0x模式下产生警告。
由于编译器生成的特殊函数的限制规则和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的兼容性,三原则在这里仍然适用。
我不敢相信没有人链接到这。
具有自定义析构函数、复制/移动构造函数或复制/移动赋值操作符的类应该专门处理所有权。 其他类不应该有自定义析构函数、复制/移动 .构造函数或复制/移动赋值操作符
在我看来,这一点很重要:
通用的“包中的所有权”类包含在标准中 库:std::unique_ptr和std::shared_ptr。通过使用 自定义删除器对象,两者都已变得足够灵活,可以进行管理
std::unique_ptr
std::shared_ptr
以下是自2011年1月24日以来的当前状态和相关发展的简短更新。
根据c++ 11标准(见附件D的[depr.impldec]):
如果类具有用户声明的复制赋值操作符或用户声明的析构函数,则不建议使用复制构造函数的隐式声明。如果类具有用户声明的复制构造函数或用户声明的析构函数,则不建议使用复制赋值操作符的隐式声明。
2013年,EWG投票反对在c++ 2014中实现这一提议。对该提案做出决定的主要理由与对破坏现有代码的普遍担忧有关。
最近,提出了再次对c++ 11的措辞进行了调整,以实现非正式的五规则,即
如果这些函数是用户提供的,则编译器不能生成复制函数、移动函数或析构函数。
如果被EWG批准,这个“规则”很可能被c++ 17采用。
简单来说,记住这一点。
0法则:
Classes have neither custom destructors, copy/move constructors or copy/move assignment operators.
Destructor, Copy constructor, copy assignment
Destructor, Copy constructor, copy assignment, move constructor, move assignment
Destructor, Copy constructor, move constructor, assignment, swap (the half part)
< >强引用< / >强:
https://www.linkedin.com/learning/c-plus-plus-advanced-topics/rule-of-five?u=67551194 https://en.cppreference.com/w/cpp/language/rule_of_three < / p >