| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> Item 17: Understand special member function generation. -> 正文阅读 |
|
[C++知识库]Item 17: Understand special member function generation. |
Item 17: Understand special member function generation.Effective Modern C++ Item 17 的学习和解读。 在 C++ 中,对于某些特殊成员函数,如果我们没有申明,编译器会自动生成它们。 在 C++98 中,这些特殊成员函数包括默认构造函数、析构函数、拷贝构造函数、拷贝赋值操作。编译器生成这些构造函数的原则是:当你没有申明它们,并且需要使用到它们。编译器生成的这些特殊函数,并且一般是 public 、 inline 和 nonvirtual 的。派生类中的析构函数有点特殊,当这个派生类继承自 virtual 析构函数的基类,在这种情况下,派生类中,编译器生成的析构函数也是 virtual 的。 两个 copy 操作是独立的:声明一个不会阻止编译器生成另外一个。所以如果你声明了一个拷贝构造函数,但是没有声明拷贝赋值操作 ,然后你需要用到拷贝赋值,编译器将帮你生成一个拷贝赋值操作。类似的,如果你声明了一个拷贝赋值操作,但没有声明拷贝构造函数,然后你的代码需要拷贝构造,编译器将帮你生成一个拷贝构造函数。 你也许听过三法则(The Rule of Three):如果你声明了任何一个拷贝构造函数,拷贝赋值操作或析构函数,那么你应该声明所有的这三个函数。三法则的建议来源于这样的:当拷贝构造、拷贝赋值或者析构函数不能胜任时候,往往是类要管理某些资源(通常是内存资源),当需要在拷贝中对资源进行管理,那么也需要在析构函数中对资源也进行管理(通常是释放内存),反之亦然。 在 C++11 中,多了两个特殊成员函数:移动构造函数和移动赋值操作:
新增的两个 move 函数生成的规则也是类似的:当你没有申明,并且代码需要使用,编译器就会替你生成。看个例子:
这个例子,编译器就会自动生成 move 构造函数。 但是,实际上当我们对一个类使用移动构造的时候,编译器并不保证一定是移动构造,因为这个类并不一定具备移动语义,这时候会用拷贝来代替。看这个例子:
这里的 A b(std::move(a)); 实际上是调用的编译器生成的拷贝构造函数。 两个 move 函数不是独立的:如果你声明了任何一个,那就阻止了编译器生成另外一个。也就是说,如果你声明了一个 move 构造函数,那就表明默认的 memberwise move 对这个类来说是不胜任的,那么编译器会认为 默认的 memberwise move 赋值函数也是不能胜任的。所以声明一个 move 构造函数会阻止一个move 复制操作函数被自动生成,声明一个 move 赋值操作函数会阻止一个 move 构造函数被自动生成。 另外,如果任何类显式地声明了一个 copy 操作,两个move 操作就不会被自动生成。这样做的理由是:声明一个 copy 操作表明了用默认的 memberwise copy 来拷贝对象对于这个类来说是不合适的,然后编译器认为,如果对于 copy 操作来说memberwise copy 不合适,那么对于 move 操作来说 memberwise move 很有可能也是不合适的。将上面第一个例子添加一个拷贝构造函数:
这个例子可以看到:定义了 copy 构造函数,阻止了编译器生成 move 构造函数。 三法则的一个结论是:当类中出现一个用户自定义的析构函数,则表示简单的 memberwise copy 可能不太适合 copy 操作。这反过来就建议:如果一个类声明了一个析构函数,copy 操作可能不应该被自动生成,因为它们可能将作出一些不正确的事。在 C++98 被采用的时候,这个原因的重要性没有被发现,所以在C++98中,用户自定义的析构函数的存在不会影响编译器生成 copy 操作。这种情况在 C++11 中还是存在的,但是这只是因为条件的限制(如果阻止 copy 操作的生成会破坏太多的遗留代码)。 但是,三法则背后的考量还是有效的,并且,结合之前的观察:copy 操作的声明阻止隐式 move 操作的生成。这使得在C++11 中,一个类中有一个用户自定义的析构函数时,则编译器不会生成 move 操作。 因此:只在下面三个条件为真的时候,编译器才为类生成 move 操作(当需要的时候):
并且,当用户自定义了 move 操作时候,编译器也会认为默认的 memberwise copy 也是不适合的,也会阻止两个 copy 函数被自动生成。 如果你想突破这些限制:用户自定义的 copy 构造函数阻止了编译器生成 move 构造函数,但是如果编译器生成的函数提供的行为是正确的,也就是说如果 memberwise move 就是你想要的,C++11的 “=default” 可以帮助你:
总结 C++11 特殊成员函数生成的规则: 默认构造函数:
析构函数:
拷贝构造函数:
拷贝 operator= :
move构造函数和move operator=:
需要注意的是:关于成员函数模板的存在,没有规则规定它会阻止编译器生成特殊成员函数。
即使这些 template 能实例化出拷贝构造函数和拷贝 operator= 的函数签名(就是 T 是 Widget 的情况),编译器仍然会为Widget 生成 copy 和 move 操作。Item 26 会解释这个边缘情况。 总结一下:
|
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 5:02:14- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |