C++中默认操作怎么定义

本篇内容主要讲解“C++中默认操作怎么定义”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++中默认操作怎么定义”吧!

C.21:默认操作要定义就全定义,要禁止就全禁止

Reason(原因)

特殊的成员函数包括构造函数,拷贝构造函数,拷贝赋值运算符,移动构造函数,移动赋值运算符和析构函数。

译者注:这些函数都具有管理数据成员生命周期的责任,因此实现还是禁止都需要统一。

特殊函数的语义紧密相关,如果一个需要声明,可能其他的也需要考虑。

定义除默认构造函数之外的所有特殊函数,即使采用=default或者=delete的形式,将会抑制隐式声明移动构造函数和移动赋值运算符。声明移动构造函数或者移动赋值运算符,即使采用=default或者=delete的形式,也会导致隐式生成的拷贝构造函数或者拷贝赋值运算符被定义为=delete。因此,一旦任何一个特殊函数被声明,其他的都应该被声明以避免多余的效果。例如将所有的潜在移动操作都被变成代价高昂的拷贝操作,或者令这个类变成只移动的。

Example, bad(反面示例)
struct M2 {   // bad: incomplete set of default operations
public:
   // ...
   // ... no copy or move operations ...
   ~M2() { delete[] rep; }
private:
   pair<int, int>* rep;  // zero-terminated set of pairs
};

void use()
{
   M2 x;
   M2 y;
   // ...
   x = y;   // the default assignment
   // ...
}

假设析构函数需要那个“特殊模式”(这里是释放内存),那么(默认的,译者注)拷贝和移动赋值(都会隐性销毁对象)正确动作的可能性就会很低。


Note(注意)

这就是众所周知的"5特殊函数规则"或者"6特殊函数规则",不同之处在于是否将默认构造函数算进来。

Note(注意)

如果需要默认操作的默认实现(例如定义了其他非默认的),通过=default表示你是有意那么做的。如果不想要默认操作,通用=delete抑制它的产生。

译者注:例如,如果定义了某种形式的构造函数,编译器就不会生成默认的构造函数。

Example, good(示例)

如果需要声明析构函数就直接定义为virtual,这个做法可以作为默认。为了避免抑制隐式的移动操作,它们也必须被声明。为了避免类成为只移动(和拷贝禁止)类型,拷贝操作也必须声明:

class AbstractBase {
public:
 virtual ~AbstractBase() = default;
 AbstractBase(const AbstractBase&) = default;
 AbstractBase& operator=(const AbstractBase&) = default;
 AbstractBase(AbstractBase&&) = default;
 AbstractBase& operator=(AbstractBase&&) = default;
};

为了避免由于规则C.67产生的分歧,也可以将拷贝和移动运算符定义为删除的。

class ClonableBase {
public:
 virtual unique_ptr<ClonableBase> clone() const;
 virtual ~ClonableBase() = default;
 ClonableBase(const ClonableBase&) = delete;
 ClonableBase& operator=(const ClonableBase&) = delete;
 ClonableBase(ClonableBase&&) = delete;
 ClonableBase& operator=(ClonableBase&&) = delete;
};

只定义移动操作或者拷贝操作产生的效果相同,但是应该明确地为每个特殊函数说明目的以便让读者更容易理解。

Note(注意)

编译器会强制执行本规则的大部分,理想情况会对任何违反发出警告。

Note(注意)

强烈反对一个具有析构函数的类依靠隐式产生的拷贝操作。

Note(注意)

同时写6个特殊成员函数容易发生错误。注意以下代码中的参数类型。

class X {
public:
   // ...
   virtual ~X() = default;            // destructor (virtual if X is meant to be a base class)
   X(const X&) = default;             // copy constructor
   X& operator=(const X&) = default;  // copy assignment
   X(X&&) = default;                  // move constructor
   X& operator=(X&&) = default;       // move assignment
};

小错误(例如拼写错误,落了const,用了&而不是&&,或者落了某个特殊成员函数)会引起错误或警告。为了避免无聊的代码和可能的错误,努力践行"0特殊函数"原则。

Enforcement(实施建议)

(简单)类应该要么声明(哪怕是通过=delete)所有的特殊函数,要么一个也不声明。

到此,相信大家对“C++中默认操作怎么定义”有了更深的了解,不妨来实际操作一番吧!这里是蜗牛博客网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:niceseo99@gmail.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

评论

有免费节点资源,我们会通知你!加入纸飞机订阅群

×
天气预报查看日历分享网页手机扫码留言评论电报频道链接