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

throw与noexcept对比

概念

throw是c++98/c++03时代就存在的说明符;noexcept关键字是c++11引入的关键字,这个关键字的引入主要用于替代throw说明符。

他们的作用类似都是用于说明一个函数是否抛出异常。

基本用法

throw基本用法

// 旧式异常说明
void oldFunction() throw();      // 保证不抛出异常
void oldFunction2() throw(std::exception);  // 可能抛出 std::exception

noexcept基本用法

// 1. 函数声明中的 noexcept
void func1() noexcept;                    // 保证不会抛出异常
void func2() noexcept(true);              // 等同于 noexcept
void func3() noexcept(false);             // 可能抛出异常
void func4() noexcept(condition);         // 条件性指定是否会抛出异常

// 2. noexcept 操作符
bool will_throw = noexcept(func1());      // 检查表达式是否会抛出异常

 性能对比

  • throw在运行时生效
  • noexcept在编译阶段,在运行阶段基本无开销。

那么如何理解上面的这段话呢?请看下面的例子:

// 使用 throw()
void example() throw() {
    try {
        // 函数体
        throw std::runtime_error("error");  // 抛出异常
    } catch (...) {
        // 如果抛出异常,运行时会:
        // 1. 调用 std::unexpected()
        // 2. 默认情况下,std::unexpected 会调用 std::terminate()
        // 3. 程序终止
    }
}

// 实际上编译器会生成类似这样的代码
void example_impl() {
    try {
        // 原始函数体
    } catch (...) {
        std::unexpected();  // 运行时检查违反异常规范
    }
}
 

通过上面的例子可以看到:编译器对于throw修饰的函数会在原函数中生成一段代码,这段代码在运行时如果检测到异常,那么就会调用编译器插入的函数std::unexcept(),并最终调用std::terminate退出程序。

 那么noexcept是什么行为呢?请看下面的例子:

// 编译器会在编译时进行静态分析
void example() noexcept {
    throw std::runtime_error("error");  // 编译错误:不允许在 noexcept 函数中抛出异常
}

// 如果运行时确实抛出了异常(比如通过函数指针调用)
void what_happens() noexcept {
    void (*fp)() = []() { throw std::runtime_error("error"); };
    fp();  // 如果执行,直接调用 std::terminate()
}

 通过上面的例子可以看到,在编译阶段就会完成与throw类似的功能。但是并不是在通过在编译阶段插入了一些函数语句来实现的,而是在编译阶段直接报错的方式。

使用建议

  • 在现代c++工程中,建议使用noexcept
  • 应避免使用throw(),它在 C++17 中被规定为等同于 noexcept,在 C++20 中被弃用

最佳实践

  1. 应该使用 noexcept 的场合

    • 移动构造函数和移动赋值运算符
    • 析构函数(默认就是)
    • 简单的getter/setter
    • 不会失败的操作
  2. 不应该使用 noexcept 的场合

    • 可能分配内存的操作
    • 可能抛出异常的系统调用
    • 复杂的操作序列

http://www.kler.cn/a/465420.html

相关文章:

  • 《深入浅出HTTPS​​​​​​​​​​​​​​​​​》读书笔记(24):椭圆曲线密码学
  • 让私域用户付费的三个关键要素
  • 通义千问API KEY操作指南
  • C++编程库与框架实战——ZeroMQ消息队列
  • QEMU网络配置简介
  • 原子类及原理和ABA问题解决
  • AI赋能跨境电商:魔珐科技3D数字人破解出海痛点
  • Flutter面试题、Dart面试题
  • SQL基础应用
  • javaEE-网络原理-1初识
  • Django 项目中的高效日志管理:从配置到实践
  • Windows平台ROBOT安装
  • Socket套接字
  • Celeborn和HDFS、YARN混合部署
  • 算法 Class 006(二分搜索)
  • SQL 基础教程 - SQL ORDER BY 关键字
  • 华为的数字化转型框架和数字化转型成熟度评估方法
  • 在C语言中使用伪终端与bash交互
  • MATLAB 车牌自动识别系统设计 图像分割与图像增强方法 车牌识别
  • linux网络 | 深度学习http的相关概念
  • k8s基础(2)—Kubernetes-Namespace
  • JAVA学习笔记_Redis进阶
  • 【数据仓库金典面试题】—— 包含详细解答
  • SQL Server导出和导入可选的数据库表和数据,以sql脚本形式
  • UML之关联
  • 【数据结构】双向循环链表的使用