当前位置: 首页 > article >正文

C++ 移动构造函数为什么设置noexcept?

答案显然是: 移动构造函数设置了noexcept后STL的容器可以显著提高性能。

For example:

class MyClass {
public:
    MyClass(int v) { val = v; }

    MyClass(const MyClass& o) {
        val = o.val;
        std::cout << "Copy constructor " << val << std::endl;
    }

    MyClass(MyClass&& o) noexcept {
        val = o.val;
        std::cout << "Move constructor " << val << std::endl;
    }

    int val = 0;
};

int main() {
    std::vector<MyClass> vec1;
    vec1.push_back(MyClass(1));
    std::cout << "insert second item:" << std::endl;
    vec1.push_back(MyClass(2));
    return 0;
}

猜测一下可能的流程:

  1. vec1没有reserve capacity,所以出事capacity是0(zero overhead)。
  2. 先push_back第一个元素,由于MyClass(1)是一个临时对象,所以调用移动构造函数。
  3. 再push_back第二个元素,这个时候超过了vec1的capacity,重新分配空间。
  4. 在重新分配的空间中,现在最后一个位置将MyClass(2)存进去,临时对象所以调用移动构造函数。
  5. 这是MyClass(1)还在原来的位置,所以需要移动到新的空间中,这时候就要决定是调用拷贝构造韩式移动构造,显然,移动构造效率更高。因此调用移动构造函数存入MyClass(1)
  6. vector在选择调用拷贝构造函数还是移动构造函数的时候会检查移动构造函数是否有noexcept,如果有则优先调用移动构造,否则调用拷贝构造函数

那为什么要看移动构造是不是 noexcept 呢,假设移动构造的内部实现可能会throw exception,那么 vector 在将旧元素移动到新空间时候,可能会触发 exception,考虑到数据的一致性,这个时候的预期结果应该是 push_back 失败,返回一个 error,然后 vector 原有数据保持不变,对吧? 但这个时候已经有一部分数据 move 到新空间了,原有数据已经被修改了,这个时候还怎么保持原有数据不变呢?

所以,使用 move 的前提就是保证(strong guarantee)移动构造不会 throw exception ,也就是 noexcept 关键字的作用,vector 看到 noexcept 就可以放心的使用 move 方案了,否则只能使用 copy 方案。

执行这个检查是 move_if_noexcept 函数,源码在这里:

template <class _Tp>
using __move_if_noexcept_result_t =
    typename conditional<!is_nothrow_move_constructible<_Tp>::value && is_copy_constructible<_Tp>::value, const _Tp&,
                         _Tp&&>::type;

template <class _Tp>
_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 __move_if_noexcept_result_t<_Tp>
move_if_noexcept(_Tp& __x) _NOEXCEPT {
  return _VSTD::move(__x);
}

最后给大家推荐一个LinuxC/C++高级架构系统教程的学习资源与课程,可以帮助你有方向、更细致地学习C/C++后端开发,具体内容请见 https://xxetb.xetslk.com/s/1o04uB


http://www.kler.cn/news/285097.html

相关文章:

  • python网络爬虫(零)——认识网页结构
  • Linux主机网络参数的设置—IP地址的作用和类型
  • LabVIEW呼吸机测试系统开发
  • sqli-labs靶场通关攻略(五十一到五十六关)
  • 【c++】日期类相关实践:计算日期到天数转换、日期差值
  • 如何打造免费体育馆场地预约系统?php vue技术实现,简易操作指南
  • Veeam Data Platform 12.2 发布下载,新增功能概览
  • K8S(Kubernates) 知识目录
  • Redis缓存的一些案例
  • 带权重的随机算法
  • 机械学习—零基础学习日志(概率论总笔记1)
  • DRF——serializer中获取嵌套评论
  • 鸿蒙HarmonyOS之使用preferences首选项保存获取数据
  • 1、Java简介+DOS命令+java的编译运行(字节码/机器码、JRE/JVM/JDK的区别)+一个简单的Java程序
  • Linux 数据结构 树知识
  • shell小白学习记录
  • 如何将线程绑定到特定的CPU核
  • HarmonyOS开发实战( Beta5版)减小应用包大小
  • 【2024】Datawhale X 李宏毅苹果书 AI夏令营 Task2
  • Linux(CentOS 7)
  • element的el-date-picker组件实现只显示年月日时分,不显示秒
  • 2024最新VMware17安装Windows10详细记录
  • SQL进阶技巧:如何查询最近一笔有效订单? | 近距离有效匹配问题
  • 微信小程序 === 组件样式
  • WHAT - 一个 IP 地址与地理信息的关联
  • JAVA中如何自定义注解
  • Docker compose 安装 ELK
  • 【电力电子】单相并网逆变器
  • 在Vue2中使用WebSocket
  • C语言基础(二十一)