C++11/14/17中的特殊成员函数
Rationale(原理部分)####
Rule of 3#####
如果隐式生成的析构函数,拷贝赋值算符,拷贝构造函数中任一不能正常工作,则三者均不能正常工作。
C++98中的generated special member function#####
由于在C++98诞生时,rule of 3的重要性没有被认识到,所以上述3者的显式声明对于编译器对它们的隐式生成没有干扰。举例来说,如果显式声明了一个析构函数,由rule of 3可知,拷贝赋值算符与拷贝构造函数肯定不能正常工作,但编译器依旧隐式生成这两者的默认版本。
C++11中的generated special member function#####
C++11诞生时,标准委员会已经充分认识到了rule of 3的重要性,并且由于C++11中 move semantics的引入,rule of 3 进化为 rule of 5,即析构函数,拷贝操作,移动操作5者中任一不能使用默认版本则全部不能使用默认版本,并且标准委员会通过标准来强制执行 rule of 5。
删除定义与默认定义####
C++11还引入了两种新的函数定义模式,删除定义与默认定义(ISO 8.4.2, ISO 8.4.3)
形式上为
function declaration = default;
function declaration = delete;
形式上与之类似的还有纯虚函数(ISO 10.4)
function declaration = 0;
Specs(细则部分)####
1.编译器会隐式定义没有被显式声明的特殊成员函数,除非被阻止(情况2)。
2.任何显式声明的构造函数阻止默认构造函数的隐式定义。(C++98)
3.Rule of 5 中任一函数的显式声明使得移动操作被隐式删除定义。(C++11)
4.移动操作的显式声明使得拷贝操作被隐式删除定义。(C++11)
5.情况3可能在C++17中扩展到拷贝操作上。(Future)
名词说明#####
1.特殊成员函数指的是构造函数,赋值算符和析构函数。
2.拷贝操作包括拷贝赋值与拷贝构造,移动操作与之同理。
实例分析####
BS在他的第四版The C++ Programming Language中犯了一个错误,引发了我写这篇文章的想法,C++他爹也会犯错: )
TC++PL 4th
chap 28.2
page 783 中有如下一个模版类定义
template<typename T>
struct Scoped {
//省略与主体无关的
Scoped(const Scoped &) = delete;
Scoped & operator=(const Scoped &) = delete;
}
C++他爹是想禁止Scoped的instance被拷贝,由细则部分第2条可知,这个类不能被默认构造,由于老爹又没提供其他的构造函数,也就是说。。这个类不能被构造。。 但是事实上他确实定义了Scoped的object。
g++ 4.8.3
clang 3.5
VS2013R4
行为均与标准一致,不过VS2013R4不支持默认定义移动操作,VS2015 Preview中已提供支持
最后附上测试代码
template<typename T>
class Test {
//下边两行存在任意一行时,默认构造函数均不应该被隐式生成
Test(const Test &) = delete;
Test(Test &&) = delete;
};
int main() {
Test<int> a;
return 0;
}