栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Item 29: Assume that move operations are not present, not cheap, and not used.

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Item 29: Assume that move operations are not present, not cheap, and not used.

Item 29: Assume that move operations are not present, not cheap, and not used.

Effective Modern C++ Item 29 的学习和解读。

在 C++11 新增特性中,移动语义无疑是最重要的一个,它允许编译器使用高效的 move 操作代替低效的 copy 操作。一般地,把你的 C++98 代码使用 C++11 编译器重新编译后,运行的会更快一些。

然而,凡是都不是绝对的,本 item 会介绍一些移动语义不可用、不那么高效的场景。

对于 C++ 标准库,针对 C++11 特性做了大量的修改,添加了对移动语义的支持,对 C++ 标准库使用移动操作基本上都会带来性能的提升。但对于我们自己存量的老代码,多数是不支持移动语义的。并且在 Item 17 中也介绍了,编译器只会在没有用户自定义拷贝操作和析构函数时才会生成移动操作。因此,这种情况下无法享受到移动语义带来的性能收益。

C++11 标准库已经都支持移动操作了,但不意味着一定都会带来性能的提升。例如 std::array,其实它本质上是披着标准库容器接口外衣的数组。一般的 STL 容器的对象,其数据成员是在堆上,对象中有一个指针指向这个堆。这个指针的存在,让容器内容的移动只要将目标容器的指针指向源容器的堆,然后将源容器的指针设置为空即可。

std::array 没有这样的指针,它的内容直接存储在对象的 buffer 中,它的移动没法像一般的容器那样通过直接改变容器中指针的指向来高效完成移动。std::array 的移动需要将数据一个一个移动或拷贝。

对于 std::string,提供了常量时间的移动和线性时间的拷贝,听起来移动比拷贝高效很多。然而,也有例外。std::string 有一种实现叫 SSO(small string optimization),对于小字符串(例如少于 15 个字符)其数据直接存储在对象中,而不存储在堆上。SSO 直接使用对象内部的 buffer 存放内容,而省去动态申请堆内存。移动基于 SSO 实现的小字符串并不会比拷贝高效。

即使对于支持移动语义的类型,看似一定使用移动的场景,却最终使用的是拷贝。Item 14 介绍了一些标准库操作提供了异常规范影响移动语义的场景。只有移动操作一定不会抛出异常的情况下,拷贝操作在内部才会被移动操作替换。如果移动操作没有被申明为 noexcept,即使是适合移动操作的场景,编译器也会依然生成拷贝操作。

此外,虽然左值可以使用 std::move 将其转换为右值进行移动操作,但会存在一些异常情况,参见 Item 25 。因而尽可能只对右值进行移动操作。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/862545.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号