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

Modern Effective C++ Item 14 如果函数不抛出异常请使用noexcept

C++11 noexcept关键字用于指定函数不会抛出异常,有助于提高程序的异常安全性,还能够使编译器生成更加高效的代码。

  1. noexcept 是函数接口的一部分

函数是否声明为 noexcept 是接口设计的一部分,客户端代码可能会依赖这一点。如果一个函数被声明为 noexcept,客户端代码可能会假设这个函数在任何情况下都不会抛出异常,从而在调用这个函数时不会进行异常处理。更改函数的 noexcept 状态会影响到依赖这个函数的客户端代码。客户端代码可能需要进行相应的调整,例如增加异常处理逻辑,以应对新的异常抛出情况。

void safeFunction() noexcept;  // 客户端代码可能依赖此函数不抛出异常

2. noexcept 函数更容易优化

编译器可以利用 noexcept 信息进行更多的优化,例如不需要为异常处理保留栈信息,从而减少运行时开销。当一个异常被抛出时,程序需要找到一个合适的异常处理程序来处理这个异常。为了做到这一点,程序需要“展开”调用栈,即逐层回溯调用栈,直到找到一个匹配的异常处理程序。

栈展开的开销:保存当前函数的上下文(寄存器状态、局部变量等)。回溯调用栈,检查每个函数的异常处理信息;析构已构造的对象,释放资源;找到并跳转到合适的异常处理程序。这些步骤需要额外的运行时支持,包括额外的内存和计算资源,从而增加了程序的运行时开销。

(1)省略栈展开信息

如果一个函数被声明为 noexcept,编译器知道这个函数不会抛出异常,因此可以省略与栈展开相关的元数据和代码。编译器不需要为 noexcept 函数生成异常表(exception table),这些表通常用于记录每个函数的异常处理信息。编译器可以在 noexcept 函数中省略与栈展开相关的代码。

(2)减少运行时检查

编译器可以减少或消除对 noexcept 函数的动态异常检查。

(3)内联优化

编译器倾向于将 noexcept 函数内联到调用点,内联可以减少函数调用的开销,提高性能。

int nonOptimizedFunction() {try {// 可能抛出异常的代码} catch (...) {// 异常处理}return 0;
}
int optimizedFunction() noexcept {// 不会抛出异常的代码return 0;
}

3. noexcept 对于移动语义、swap、内存释放函数和析构函数非常有用

对于移动操作和 swap,声明为 noexcept 可以提高性能,因为编译器可以更安全地优化这些操作。内存释放函数和析构函数默认是 noexcept 的,因为它们不应该抛出异常。

class Widget {
public:Widget(Widget&& other) noexcept;// 移动构造函数void swap(Widget& other) noexcept;// 交换函数
};
template <class T, size_t N>
void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b)));
template <class T1, class T2>
struct pair {void swap(pair& p) noexcept(noexcept(swap(first, p.first)) && noexcept(swap(second, p.second)));
};

(1)移动语义

声明为 noexcept 可以告诉编译器移动构造函数不会抛出异常,从而允许编译器进行优化。移动操作通常比复制操作更快,因为它们只需转移资源的所有权,而不是复制资源。如果移动操作是 noexcept 的,编译器可以更安全地使用移动操作来优化代码。

class Widget {
public:Widget(Widget&& other) noexcept;  // 移动构造函数
};

Widget 类的移动构造函数被声明为 noexcept,表示这个操作不会抛出异常。编译器可以利用这一点进行优化,例如在 std::vector 的 push_back 操作中优先使用移动操作。

(2)swap 函数

swap 函数用于交换两个对象的内容。声明为 noexcept 可以提高性能,因为编译器可以更安全地优化 swap 操作。swap 操作通常涉及多个赋值和移动操作。如果这些操作是 noexcept 的,编译器可以更自由地进行优化,例如内联和减少异常处理的开销。

class Widget {
public:void swap(Widget& other) noexcept;  // 交换函数
};

Widget 类的 swap 函数被声明为 noexcept,表示这个操作不会抛出异常。编译器可以利用这一点进行优化,例如在 std::sort 等算法中优先使用 swap 操作。

(3)noexcept 对于内存释放函数和析构函数

内存释放函数(如 operator delete 和 operator delete[])用于释放动态分配的内存。这些函数默认是 noexcept 的,因为它们不应该抛出异常。如果内存释放函数抛出异常,程序将处于不确定的状态,可能导致资源泄露或其他严重问题。因此,默认情况下,这些函数是 noexcept 的,以确保程序的稳定性。析构函数用于释放对象占用的资源。这些函数默认是 noexcept 的,因为它们不应该抛出异常。如果析构函数抛出异常,可能会导致未定义行为,特别是在标准库容器和算法中。例如,如果 std::vector 中的元素的析构函数抛出异常,可能会导致 std::vector 的析构函数无法正常完成,从而导致资源泄露。

class Widget {
public:~Widget() noexcept;  // 析构函数
};

Widget 类的析构函数被声明为 noexcept,表示这个操作不会抛出异常。编译器可以利用这一点进行优化,如在 std::vector 的析构过程中更安全地释放资源。

4. 异常中立的函数不加no except

大多数函数是异常中立的,即它们自己不抛异常,但可能调用其他会抛异常的函数。这些函数不应该声明为 noexcept,因为它们可能传递异常。

void exceptionNeutralFunction() {someOtherFunction();  // 可能抛出异常
}

虽然 noexcept 可以带来性能提升,但不应该为了 noexcept 而扭曲函数的实现。如果一个函数的实现可能会抛出异常,强行捕获异常并转换为状态码或特殊返回值会使代码变得复杂且难以维护。

5. 区分宽泛契约和严格契约的函数

宽泛契约的函数没有前置条件,可以随时调用,不应表现出未定义行为,无论程序状态如何,都可以安全地调用这些函数。严格契约的函数有前置条件,违反前置条件会导致未定义行为。对于严格契约的函数,即使它自然不会抛出异常,也应该谨慎声明 noexcept,因为前置条件的检查可能需要抛出异常。

void wideContractFunction() noexcept {// 没有前置条件,自然不会抛出异常
}

严格契约函数

严格契约的函数有前置条件,调用者必须确保这些前置条件满足。如果违反前置条件,函数的行为是未定义的。函数有特定的输入要求,调用者必须确保这些要求满足。如果前置条件不满足,函数的行为是未定义的,可能会导致程序崩溃或其他不可预测的行为。谨慎声明 noexcept,即使这些函数自然不会抛出异常,也应该谨慎声明为 noexcept,因为前置条件的检查可能需要抛出异常。

void narrowContractFunction(const std::string& s) noexcept{assert(s.length() <= 32);
}

相关文章:

Modern Effective C++ Item 14 如果函数不抛出异常请使用noexcept

C11 noexcept关键字用于指定函数不会抛出异常&#xff0c;有助于提高程序的异常安全性&#xff0c;还能够使编译器生成更加高效的代码。 noexcept 是函数接口的一部分 函数是否声明为 noexcept 是接口设计的一部分&#xff0c;客户端代码可能会依赖这一点。如果一个函数被声明…...

cudatoolkit安装(nvcc -V错误版本解决)

CudaToolKit安装&#xff08;nvcc&#xff09; cudatoolkit 是 CUDA 开发工具包&#xff08;CUDA Toolkit&#xff09; 的核心部分&#xff0c;包含了一系列用于开发和运行 CUDA 应用程序的软件组件。nvcc 是 NVIDIA CUDA 编译器驱动&#xff0c;用于将 CUDA C/C 代码编译成可…...

DTO和VO的区别及使用场景详解

随着互联网的发展&#xff0c;前后端分离的开发模式越来越流行。在前后端数据交互过程中&#xff0c;为了保证数据的安全性和效率&#xff0c;通常会采用 DTO 和 VO 来封装数据。本篇博客将详细介绍 DTO 和 VO 的区别以及使用场景。 大家可能会有个疑问&#xff0c;既然DTO是展…...

百度在下一盘大棋

这两天世界互联网大会在乌镇又召开了。 我看到一条新闻&#xff0c;今年世界互联网大会乌镇峰会发布“2024 年度中国互联网企业创新发展十大典型案例”&#xff0c;百度文心智能体平台入选。 这个智能体平台我最近也有所关注&#xff0c;接下来我就来讲讲它。 百度在下一盘大棋…...

第十六届蓝桥杯模拟赛第二期题解—Java

第十六届蓝桥杯模拟赛/校赛第二期个人题解&#xff0c;有错误的地方欢迎各位大佬指正 问题一(填空题) 【问题描述】 如果一个数 p 是个质数&#xff0c;同时又是整数 a 的约数&#xff0c;则 p 称为 a 的一个质因数。 请问&#xff0c; 2024 的最大的质因数是多少&#xff1f; …...

驱动开发笔记:关于3588GPIO

1.概要 2.内容 1.3588GPIO 关于RK3588的GPIO&#xff08;General-Purpose Input/Output&#xff0c;通用输入输出引脚&#xff09;&#xff0c;以下是一些关键信息和操作指南&#xff1a; 一、GPIO基本概念 定义&#xff1a;GPIO是嵌入式系统中常见的通信接口&#xff0c;…...

【RK3588 Linux 5.x 内核编程】-内核线程与Mutex

内核线程与Mutex 文章目录 内核线程与Mutex1、Mutex介绍1.1 竞争条件1.2 Mutex特性2、Linux内核中的Mutex2.1 初始化Mutex2.1.1 静态方式初始化2.1.2 动态方式初始化2.2 互斥锁获取2.3 互斥锁释放3、Mutex使用示例4、驱动验证在前面的文章中,介绍了如何Linux内核中的线程,但是…...

【0342】分配并初始化 Proc Signal 共享内存 (1)

1. Proc Signal (procsignal)共享内存 Postgres内核在启动postmaster守护进程时候, 会通过函数 ProcSignalShmemInit() 去为 Proc Signal 分配并初始化指定大小的共享内存空间。整个调用链路如下。 (gdb) bt #0 ProcSignalShmemInit () at procsignal.c:118 #1 0x000000000…...

管家婆财贸ERP BR035.回款利润明细表

最低适用版本: 财贸系列 23.5 插件简要功能说明: 报表统计销售单/销售退货单/销售发票回款情况更多细节描述见下方详细文档插件操作视频: 进销存类定制插件--回款利润明细表 插件详细功能文档: 1. 应用中心增加报表【回款利润明细表】 a. b. 查询条件: ⅰ. 日期区间:…...

数据库MYSQL——表的设计

文章目录 前言三大范式&#xff1a;几种实体间的关系&#xff1a;一对一关系&#xff1a;一对多关系&#xff1a;多对多关系&#xff1a; 前言 之前的博客中我们讲解的是关于数据库的增删改查与约束的基本操作&#xff0c; 是在已经创建数据库&#xff0c;表之上的操作。 在实…...

netstat -tuln | grep 27017(显示所有监听状态的 TCP 和 UDP 端口,并且以数字形式显示地址和端口号)

文章目录 1. 确定占用端口的进程使用 lsof 命令使用 fuser 命令 2. 结束占用端口的进程3. 修改 MongoDB 配置文件4. 检查 MongoDB 日志文件5. 重新启动 MongoDB 服务6. 检查 MongoDB 服务状态总结 [rootlocalhost etc]# netstat -tuln | grep 27017 tcp 0 0 127.0.…...

非线性控制器设计原理

非线性控制器设计原理 非线性控制器设计旨在解决非线性系统的控制问题&#xff0c;克服传统线性控制器在处理非线性现象&#xff08;如饱和、死区、耦合、时变性等&#xff09;时的不足。其核心在于利用非线性数学工具和设计方法&#xff0c;使控制系统在非线性条件下具备良好…...

MySQL数据库6——SQL优化

一.SQL优化 1.插入优化 优化1&#xff1a;批量插入 insert into 表名 values(记录1),(记录2),……;优化2&#xff1a;手动提交事务 start transaction; insert into 表名 values(记录1),(记录2); insert into 表名 values(记录1),(记录2); …… commit;优化3&#xff1a;主键顺…...

IDEA配置本地maven

因为idea和maven是没有直接关系的。所以使用idea创建maven工程之前需要将本地的maven配置到idea环境中&#xff0c;这样才可以在idea中创建maven工程。配置方法如下&#xff1a; 1.1 配置本地maven 第一步&#xff1a;关闭当前工程&#xff0c;回到idea主界面找到customize--…...

学习日记_20241123_聚类方法(高斯混合模型)续

前言 提醒&#xff1a; 文章内容为方便作者自己后日复习与查阅而进行的书写与发布&#xff0c;其中引用内容都会使用链接表明出处&#xff08;如有侵权问题&#xff0c;请及时联系&#xff09;。 其中内容多为一次书写&#xff0c;缺少检查与订正&#xff0c;如有问题或其他拓展…...

SpringMVC——简介及入门

SpringMVC简介 看到SpringMVC这个名字&#xff0c;我们会发现其中包含Spring&#xff0c;那么SpringMVC和Spring之间有怎样的关系呢&#xff1f; SpringMVC隶属于Spring&#xff0c;是Spring技术中的一部分。 那么SpringMVC是用来做什么的呢&#xff1f; 回想web阶段&#x…...

文件操作完成后,为什么要关闭文件

原因包括&#xff1a; 释放系统资源&#xff1a;打开文件时&#xff0c;操作系统会分配资源&#xff0c;如文件描述符或句柄&#xff0c;用于管理文件访问。如果文件保持打开状态&#xff0c;这些资源就不会被释放&#xff0c;可能导致资源耗尽。 确保数据完整性&#xff1a;写…...

vue3+echarts+ant design vue实现进度环形图

1、代码 <div> <!-- 目标环形图 --><div id"main" class"chart_box"> </div><div class"text_target">目标</div> </div>// 目标环形图 const onEcharts () > {// 基于准备好的dom&#xff0c;初…...

使用argo workflow 实现springboot 项目的CI、CD

文章目录 基础镜像制作基础镜像设置镜像源并安装工具git下载和安装 Maven设置环境变量设置工作目录默认命令最终dockerfile 制作ci argo workflow 模版volumeClaimTemplatestemplatesvolumes完整workflow文件 制作cd argo workflow 模版Workflow 结构Templates 定义创建 Kubern…...

C++知识点总结(58):序列型动态规划

动态规划Ⅰ 一、基础1. 意义2. 序列 dp 解法 二、例题1. 最大子段和2. 删数最大子段和&#xff08;数据强度&#xff1a;pro max&#xff09;3. 最长上升子序列&#xff08;数据强度&#xff1a;pro max&#xff09;4. 3 或 5 的倍数序列5. 数码约数序列 一、基础 1. 意义 动…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...