C++ 语言特性20 - noexcept 关键字

news/2024/10/5 1:28:18/

一:概述

        noexcept 是 C++11 引入的一个关键字,用来指明一个函数在运行时是否不会抛出异常。它主要用于提高代码的安全性和性能,在某些场合可以帮助编译器进行优化。

1.  noexcept 的语法

//1. 标记函数为 noexcept, 在这种情况下,func 承诺不会抛出异常
void func() noexcept {// 函数体
}//2. 带条件的 noexcept
//noexcept 关键字也可以根据条件来动态判断一个函数是否是 noexcept。其条件必须是编译时常量表达式:
void func() noexcept(true);   // 一定不会抛出异常
void func() noexcept(false);  // 可能会抛出异常//在下面例子中,func 是否是 noexcept 取决于 some_other_func 是否是 noexcept 的。如果 some_other_func 是 noexcept,那么 func 也是 noexcept。
template <typename T>
void func(T&& t) noexcept(noexcept(some_other_func(std::forward<T>(t)))) {some_other_func(std::forward<T>(t));
}//3. noexcept 运算符
//C++ 提供了 noexcept 运算符,允许在编译时判断某个表达式是否为 noexcept。返回值是一个 bool 值,表示表达式是否不会抛出异常:
bool isNoexcept = noexcept(func());  // 如果 func 是 noexcept,返回 true

2. noexcept 的作用

  • 指定函数不抛出异常noexcept 表示一个函数承诺不会抛出任何异常。通过标记为 noexcept,编译器可以做更多的优化,例如跳过额外的异常处理机制。

    • 如果一个函数标记为 noexcept,但在运行时抛出了异常,程序会直接调用 std::terminate,结束程序的运行,而不会传播异常。

    • noexcept 可以用来提升代码的鲁棒性,使得调用方知道某些函数是不会抛出异常的。

  • 启用编译器优化: 在某些情况下,编译器可以为标记为 noexcept 的函数进行更多的优化。例如,当对象被复制或移动时,如果移动构造函数是 noexcept 的,标准容器如 std::vector 可以选择更高效的移动操作而不是复制操作。

二:使用场合

  • 移动构造函数和移动赋值运算符: 标记移动构造函数和移动赋值运算符为 noexcept 是非常重要的。当标准容器(如 std::vectorstd::deque)进行内存重新分配时,如果对象的移动操作是 noexcept 的,那么容器可以选择移动对象而不是复制对象,从而提升性能。
class MyClass {
public:MyClass(MyClass&&) noexcept;  // 移动构造函数MyClass& operator=(MyClass&&) noexcept;  // 移动赋值运算符
};//例如,当 std::vector 增长时,它需要移动现有元素到新的存储位置。如果移动构造函数是 noexcept 的,std::vector 会执行移动操作;否则,它会执行较慢的复制操作。
  • 不抛出异常的函数: 对于一些明确不会抛出异常的函数,使用 noexcept 可以帮助编译器生成更高效的代码。特别是一些低层次的库函数,比如内存管理相关的函数、数学运算函数、或对象析构函数等,通常标记为 noexcept 
void fastMathOperation() noexcept {// 这个函数不会抛出任何异常
}
  •  析构函数: 根据 C++ 标准,析构函数默认是 noexcept 的。即便不显式声明,析构函数通常不应该抛出异常。在某些场合下,特别是资源管理类(如 RAII 类),确保析构函数是 noexcept 的很重要。RAII(Resource Acquisition Is Initialization,资源获取即初始化)
class MyClass {
public:~MyClass() noexcept {  // 确保析构时不抛出异常// 清理代码}
};
  • 标准库中的使用: C++ 标准库广泛使用了 noexcept,尤其是在 std::move_if_noexcept 中。该函数用于决定是使用移动构造函数还是复制构造函数。当移动构造函数被标记为 noexcept 时,std::move_if_noexcept 会使用移动构造函数;否则,使用复制构造函数。
template <typename T>
typename std::conditional<!std::is_nothrow_move_constructible<T>::value && std::is_copy_constructible<T>::value,const T&, T&&>::type
move_if_noexcept(T& x) noexcept;
  •  模板元编程中的使用: 在模板元编程中,通过 noexcept 可以在不同的条件下生成不同的函数版本。例如,只有当某个操作不会抛出异常时,某个特定的版本才会被选择。

三:注意事项

  • noexcept 与异常的实际抛出: 如果标记为 noexcept 的函数抛出了异常,程序不会传播异常,而是直接调用 std::terminate 终止程序。因此,务必确保标记为 noexcept 的函数真的不会抛出异常。
     
  • 条件 noexcept 的使用: 使用条件 noexcept 时,确保条件表达式在编译时能够计算为常量。这样可以动态地决定函数是否应标记为 noexcept,从而在不同的场景下启用不同的异常处理机制。
     
  • 性能优化noexcept 关键字会帮助编译器进行优化,但这些优化在大多数情况下是微小的,尤其是对于非性能关键的代码,不需要过度使用 noexcept。但是,对于性能敏感的代码(如标准容器的实现、库函数等),合理使用 noexcept 可以带来显著的优化。
     
  • throw() 的区别: 在 C++11 之前,throw() 用于指定函数不抛出任何异常,但它已被 noexcept 取代。现在建议使用 noexcept 而不是 throw(),因为 throw() 已被弃用。


http://www.ppmy.cn/news/1534675.html

相关文章

python-鸡尾酒疗法/图像相似度/第n小的质数

一&#xff1a;鸡尾酒疗法 题目描述 鸡尾酒疗法&#xff0c;原指“高效抗逆转录病毒治疗”&#xff08;HAART&#xff09;&#xff0c;由美籍华裔科学家何大一于 1996 年提出&#xff0c;是通过三种或三种以上的抗病毒药物联合使用来治疗艾滋病。该疗法的应用可以减少单一用药产…

鸿蒙HarmonyOS开发生态

1、官网 华为开发者联盟-HarmonyOS开发者官网&#xff0c;共建鸿蒙生态 2、开发工具IDE下载及使用 https://developer.huawei.com/consumer/cn/ 3、使用帮助文档 4、发布到华为应用商店 文档中心

《重生到现代之从零开始的C语言生活》—— 结构体和位段

结构体 我们在之前是了解过结构体的&#xff0c;现在我们来稍微复习一下 结构体的声明 struct name {member list }&#xff1b;假如我想创建一个结构体呢么我们可以 struct a {int a;char b[20];float c; };这是我们创建了这个结构体&#xff0c;当我们想初始化时 #inclu…

详细介绍:API 和 SPI 的区别

文章目录 Java SPI (Service Provider Interface) 和 API (Application Programming Interface) 的区别详解目录1. 定义和目的1.1 API (Application Programming Interface)1.2 SPI (Service Provider Interface) 2. 使用场景2.1 API 的应用场景2.2 SPI 的应用场景 3. 加载和调…

【2024】基于mysqldump的数据备份与恢复

基于mysqldump备份与恢复 mysqldump是一个用于备份 MySQL 数据库的实用工具。 它可以将数据库的结构&#xff08;如数据库、表、视图、存储过程等的定义&#xff09;和数据&#xff08;表中的记录&#xff09;导出为文本文件&#xff0c;这些文本文件可以包含 SQL 语句&#…

【PostgreSQL】入门篇——索引:提高查询性能的利器

1. 索引的概念 描述 索引是数据库表中一个或多个列的值的有序列表。它类似于书籍的目录&#xff0c;可以帮助数据库快速定位到存储在表中的数据。 索引的主要目的是提高数据检索的速度&#xff0c;尤其是在处理大量数据时。 作用 加速查询&#xff1a;通过减少需要扫描的数…

【笔记】平面

一、平面及其方程&#xff08;3个条件&#xff0c;4种表达&#xff09; F ( x , y , z ) F(x,y,z) F(x,y,z)为平面方程&#xff1a; 在这个平面上的点满足 F ( x , y , z ) 0 F(x,y,z)0 F(x,y,z)0不在这个平面上的点不满足 F ( x , y , z ) 0 F(x,y,z)0 F(x,y,z)0 归根结底&…

泛型中的通配符<?>、<? extends T>、<? super T>的使用场景。ArrayList与LinkedList的区别及适用场景。

泛型中的通配符<?>、<? extends T>、<? super T>的使用场景。 在Java中&#xff0c;泛型通配符&#xff08;wildcards&#xff09;提供了一种灵活的方式来处理泛型类型&#xff0c;使得代码更加通用和类型安全。泛型通配符主要有三种形式&#xff1a;<…