本篇内容主要讲解“C++中默认操作怎么定义”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++中默认操作怎么定义”吧!
C.21:默认操作要定义就全定义,要禁止就全禁止
特殊的成员函数包括构造函数,拷贝构造函数,拷贝赋值运算符,移动构造函数,移动赋值运算符和析构函数。
译者注:这些函数都具有管理数据成员生命周期的责任,因此实现还是禁止都需要统一。
特殊函数的语义紧密相关,如果一个需要声明,可能其他的也需要考虑。
定义除默认构造函数之外的所有特殊函数,即使采用=default或者=delete的形式,将会抑制隐式声明移动构造函数和移动赋值运算符。声明移动构造函数或者移动赋值运算符,即使采用=default或者=delete的形式,也会导致隐式生成的拷贝构造函数或者拷贝赋值运算符被定义为=delete。因此,一旦任何一个特殊函数被声明,其他的都应该被声明以避免多余的效果。例如将所有的潜在移动操作都被变成代价高昂的拷贝操作,或者令这个类变成只移动的。
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
// ...
}
假设析构函数需要那个“特殊模式”(这里是释放内存),那么(默认的,译者注)拷贝和移动赋值(都会隐性销毁对象)正确动作的可能性就会很低。
这就是众所周知的"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(注意)
强烈反对一个具有析构函数的类依靠隐式产生的拷贝操作。
同时写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++中默认操作怎么定义”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。