C++ RAII
RAII(Resource Acquisition Is Initialization,资源获取即初始化)是 C++ 编程中的核心设计理念,用于管理资源的分配和释放。它通过将资源的生命周期绑定到对象的生命周期,利用 C++ 的自动对象管理机制(主要是栈对象的构造和析构),确保资源在使用完毕后被正确释放,避免资源泄漏。
RAII 的核心思想是资源获取(如内存、文件句柄、锁、网络连接等)在对象构造时完成。资源释放在对象析构时自动完成。利用 C++ 的栈对象生命周期,当对象离开作用域(无论是正常退出还是抛出异常)时,析构函数会自动调用,确保资源正确清理。
RAII 是 C++ 异常安全性和资源管理的基石,广泛应用于标准库和现代 C++ 编程。
RAII 的工作原理在对象的构造函数中获取资源(如分配内存、打开文件、加锁)。资源的释放逻辑在析构函数中实现。C++ 保证栈上对象离开作用域时,其析构函数会被自动调用。资源释放无需程序员手动干预。即使抛出异常,栈解退(stack unwinding)机制确保对象按逆序析构,防止资源泄漏。
管理动态分配内存的 RAII 示例:
#include <iostream>class Resource {int* data; // 动态分配的资源
public:Resource() {data = new int(42); // 构造函数获取资源std::cout << "Resource acquired: " << *data << std::endl;}~Resource() {delete data; // 析构函数释放资源std::cout << "Resource released" << std::endl;}int getValue() const { return *data; }
};void useResource() {Resource r; // 栈上对象,自动管理std::cout << "Using resource: " << r.getValue() << std::endl;
} // r 离开作用域,自动调用析构函数int main() {useResource();return 0;
}
输出:
Resource acquired: 42
Using resource: 42
Resource released
在这个例子中:构造函数分配内存(new int
)。析构函数释放内存(delete data
)。栈对象 r
离开作用域时自动释放资源,即使发生异常也能保证清理。
RAII 在 C++ 中应用广泛,以下是常见场景:
1.动态内存管理:标准库的智能指针(如 std::unique_ptr
和 std::shared_ptr
)是 RAII 的经典实现。
示例:
#include <memory>
void example() {std::unique_ptr<int> ptr = std::make_unique<int>(10);// 使用 ptr
} // ptr 离开作用域,内存自动释放
2.文件管理:std::fstream
(如 std::ifstream
、std::ofstream
)使用 RAII 管理文件句柄。
示例:
#include <fstream>
void writeFile() {std::ofstream file("example.txt");file << "Hello, RAII!";
} // file 离开作用域,自动关闭文件
3.互斥锁管理:std::lock_guard
和 std::unique_lock
使用 RAII 管理线程同步中的锁。
示例:
#include <mutex>
std::mutex mtx;
int counter = 0;void increment() {for (int i = 0; i < 1000; ++i) {std::lock_guard<std::mutex> lock(mtx); // RAII 管理锁++counter;} // lock 离开作用域,自动解锁
}
4.其他资源:网络连接(如 std::socket
封装),数据库连接,图形资源(如 OpenGL 上下文)。
RAII 的优点:资源释放由析构函数自动完成,避免手动调用 delete
、close
等。栈解退机制确保即使抛出异常,资源也能正确释放。减少手动管理资源的代码,降低出错概率。资源在对象离开作用域时立即释放,行为可预测。
注意:不要在 RAII 对象之外手动释放资源(如 delete ptr.get()
),否则可能导致未定义行为。析构函数应标记为 noexcept
,避免抛出异常,否则可能导致程序终止(std::terminate
)。独占资源(如 std::unique_ptr
)通常禁用拷贝,允许移动。共享资源(如 std::shared_ptr
)需明确定义拷贝语义。RAII 对象的构造和析构可能引入少量开销,但通常被安全性和简洁性抵消。
C++ 不提供 finally
结构,因为 RAII 提供了更优雅、系统化的替代方案。finally
通常用于确保资源在代码块结束时释放,但 RAII 通过将资源管理封装在对象中,析构函数自动释放资源实现相同的目标,且更简洁。在大型系统中,资源获取次数远多于资源种类。RAII 通过为每种资源定义一个“句柄”类,复用清理逻辑,而 finally
需要为每次获取重复编写清理代码。RAII 利用栈解退机制,确保异常发生时资源仍被释放。finally
也能做到,但需要手动管理,容易遗漏。
RAII 是最简单、系统化的防止泄漏方法,利用对象的生命周期自动管理资源。
错误示例(可能泄漏):
void f1(int i) {int* p = new int[12];if (i < 17) throw Bad{"in f()", i};// 抛出异常,未释放 p
}
手动释放(繁琐且易错):
void f2(int i) {int* p = new int[12];if (i < 17) {delete[] p; // 手动释放throw Bad{"in f()", i};}delete[] p; // 正常退出时释放
}
代码冗长,多个 throw
点需要重复释放逻辑,容易遗漏。
使用 RAII(推荐):
void f3(int i) {auto p = std::make_unique<int[]>(12);if (i < 17) throw Bad{"in f()", i};// p 离开作用域,自动释放
}
std::unique_ptr
管理内存,异常安全且简洁。
更优选择(本地对象):
void f5(int i) {std::vector<int> v(12);helper(i); // 可能抛出异常// v 离开作用域,自动释放
}
使用 std::vector
替代裸指针,更安全且高效。
隐式异常:
void f4(int i) {auto p = std::make_unique<int[]>(12);helper(i); // 可能抛出异常// p 自动释放
}
即使 helper
抛出异常,p
仍会被正确释放。
如果无法定义 RAII 对象,可使用 final_action
作为最后手段,但优先使用 RAII。
在禁用异常的场景(如嵌入式系统),可通过为资源句柄添加 valid()
检查,验证构造是否成功来模拟 RAII,示例代码如下:
void f() {vector<string> vs(100); // 自定义 vector,带 valid()if (!vs.valid()) { /* 处理错误 */ }ifstream fs("foo"); // 自定义 ifstream,带 valid()if (!fs.valid()) { /* 处理错误 */ }
} // 析构函数照常清理
这种方法缺点是代码量增加,需手动检查 valid()
,且无法隐式传播错误。
禁用异常的场景包括极小型系统(内存不足,如 2K),硬实时系统(无法保证异常处理时间),遗留代码(指针使用复杂,缺乏所有权策略),异常实现效率低(慢、内存占用大或动态链接库支持差),管理决策(需挑战传统观念)。除非有充分理由,优先使用异常实现 RAII。
RAII 体现了 C++ 的“用对象管理资源”哲学,是现代 C++(C++11 及以后)的基石。
相关文章:
C++ RAII
RAII(Resource Acquisition Is Initialization,资源获取即初始化)是 C 编程中的核心设计理念,用于管理资源的分配和释放。它通过将资源的生命周期绑定到对象的生命周期,利用 C 的自动对象管理机制(主要是栈…...
Linux进程学习【环境变量】进程优先级
进程优先级的基本概念 在 Linux 中,每个进程都有一个优先级,操作系统根据这个优先级来决定进程的执行顺序。优先级越高,进程的执行就越频繁。通常,进程优先级是由以下两个部分构成: 静态优先级(PRI&#x…...
Leetcode:283. 移动零
题目 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: nums [0]…...
BIOES 标签的含义
BIOES 标签的含义 B (Begin) 表示一个实体的开始。例如,在句子 “北京是中国的首都” 中,“北京” 作为地点实体的开头,首字会被标注为 B-LOC,后续字可能标注为 I-LOC。 I (Inside) 表示一个实体的中间或内部部分。例如&a…...
mAh 与 Wh:电量单位的深度解析
1. 基础定义与物理意义 1.1 mAh(毫安时) 定义:表示电池以毫安(mA)为单位的电流持续放电 1 小时的电荷量。1 mAh1 mA1 h3.6 C(库仑,电荷单位)局限性:仅反映电池存储的电荷量,未考虑电…...
安卓屏播放语音失败,报错TextToSpeech: speak failed: not bound to TTS engine
最近碰到一个很棘手的问题,无缘无故,之前在Android9.0跑得好好的程序,升级安装系统到Android13后,就发现之前能放的语音,现在放不了了,真是头大,所以我摸索着尝试解决,且看我的解决过…...
C语言学习之结构体
在C语言中,我们已经学了好几种类型的数据。比如整型int、char、short等,浮点型double、float等。但是这些都是基本数据类型,而这些数据类型应用在实际编程里显然是不够用的。比如我们没有办法用一旦数据类型来定义一个”人“的属性。因此这里…...
layui获取无法获取表单数据,data.field一直为空
form.on(submit(*), function(data){console.log(data.field) //当前容器的全部表单字段,名值对形式:{name: value}return false; //阻止表单跳转。如果需要表单跳转,去掉这段即可。}); console.log(data.field)一直显示为空࿰…...
「Mac畅玩AIGC与多模态02」部署篇01 - 在 Mac 上部署 Ollama + Open WebUI
一、概述 本篇介绍如何在 macOS 环境下本地部署 Ollama 推理服务,并通过 Open WebUI 实现可视化交互界面。该流程无需 CUDA 或专用驱动,适用于 M 系列或 Intel 芯片的 Mac,便于快速测试本地大语言模型能力。 二、部署流程 1. 环境准备 安装 Homebrew(如尚未安装):/bin…...
量子力学:量子通信
量子通信是利用量子力学原理对信息进行编码、传输和处理的新型通信方式,以下是其详细介绍及业界发展现状: 基本原理 量子叠加态 :量子系统可以处于多个状态的叠加,如光子的偏振方向可以同时处于水平和垂直方向的叠加态ÿ…...
《大型网站技术架构-核心原理与案例分析》笔记
:::info 💡 根据 遗忘曲线:如果没有记录和回顾,6天后便会忘记75%的内容 读书笔记正是帮助你记录和回顾的工具,不必拘泥于形式,其核心是:记录、翻看、思考::: 书名大型网站技术架构-核心原理与案例分析作者…...
log4cpp进阶指南
📝 log4cpp进阶指南 1. 按天切割日志 log4cpp 默认是按文件大小来切割日志的。为了按天切割日志,通常需要自己进行时间判断并手动处理日志文件的切割。 1.1 解决方案 虽然 RollingFileAppender 只支持按大小切割,但你可以使用以下策略&…...
树莓派超全系列教程文档--(43)树莓派内核简介及更新
树莓派内核简介及更新 简介更新 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 简介 Raspberry Pi 内核是 托管在 GitHub 上;更新滞后于上游 Linux内核。上游内核持续更新,而 Raspberry Pi 则将 Linux 内核的长期版本整合…...
第二章、在Windows上部署Dify:从修仙小说到赛博飞升的硬核指南
第1章:安装 wsl (Windows Subsystem for Linux) 上一章我们聊了什么是Dify,这一章我们讲一下怎么才能用Dify。 使用Dify就需要我们在本地部署Dify; 部署Dify就需要用到”Docker“; 要想使用“Docter”就需要用到wsl。 那什么是wsl呢?简单来说就是让你的电脑拥有另一个叫…...
淘宝商品主图标题api接口
1、输入淘宝商品id或者链接,点查询 2、查询淘宝商品主图,商品标题,商品价格,卖家旺旺 3、支持api接口...
小结:BFD
*BFD(双向转发检测,Bidirectional Forwarding Detection)是一种快速、轻量级的故障检测机制,用于检测网络中两点之间的连通性。它广泛应用于各种场景 1. 检测 IP 链路 应用场景: BFD 用于检测两台设备之间的 IP 层连…...
收藏按钮变色问题
1.问题描述 无论是否收藏,收藏按钮都显示黄色,但点击收藏按钮后却能发生颜色变化 2.解决思路 经过调试发现isCollected返回的是整个对象,因此在store的方法里面找到了相应的函数进行修改使得isCollected返回相应的值 修改前: 修…...
小程序发布后,不能强更的情况下,怎么通知到用户需要去更新?
哈喽,我想和大家分享一下我在开发记账小程序时遇到的一个问题,以及我找到的解决办法。 这个记账小程序从一开始,我就特别在意用户的隐私,所以把记账数据都存到了本地缓存里,还做了个手动备份的功能。但系统嘛…...
4.2.2 MySQL索引原理以及SQL优化
文章目录 4.2.2 MySQL索引原理以及SQL优化1. 索引与约束1. 索引是什么2. 索引的目的3. 几种索引4. 约束1.外键2. 约束 vs 索引的区别 5. 索引实现1. 索引存储2. 页3. B树4. B树层高问题5. 自增id6. 聚集索引7. 辅助索引 8. innnodb体系结构1. buffer pool2. change buffer 9. 最…...
02_值相同、类型不同,用 equals() 比较为什么是 false?
02_值相同、类型不同,用 equals() 比较为什么是 false? 场景示例 Map<Long, String> map; Integer keyWord 4; if (map.containsKey(keyWord)) {// ... }结果: → 编译通过,但 containsKey 返回 false,逻辑错…...
leetcode--盛最多水的容器,接雨水
11.盛最多水的容器 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明:你不…...
AlexNet网络搭建
AlexNet网络模型搭建 环境准备 首先在某个盘符下创建一个文件夹,就叫AlexNet吧,用来存放源代码。 然后新建一个python文件,就叫plot.py吧,往里面写入以下代码,用于下载数据集: # FashionMNIST里面包含了…...
常用第三方库:sqflite数据库应用
常用第三方库:sqflite数据库应用 一、基础概念 1.1 什么是sqflite? sqflite是Flutter官方推荐的SQLite数据库插件,它提供了在Flutter应用中使用SQLite数据库的能力。SQLite是一个轻量级的、嵌入式的关系型数据库,特别适合移动应…...
【论文阅读】-周总结-第5周
1. 【论文阅读24】并行 TCN-LSTM 风电预测模型(2024-02) 链接 论文信息: Liu S, Xu T, Du X, et al. A hybrid deep learning model based on parallel architecture TCN-LSTM with Savitzky-Golay filter for wind power prediction. Ener…...
深入理解 JavaScript 的 typeof 运算符:返回的数据类型
JavaScript 的 typeof 运算符是开发中用于检测值类型的基础工具。虽然看似简单,但其行为存在需要开发者理解的微妙细节。本文将解析 typeof 返回的数据类型,探讨边界案例,并分享类型检查的最佳实践。 typeof 会返回哪些类型? typ…...
前端零基础入门到上班:【Day8】JavaScript 基础语法入门
前端零基础入门到上班:【Day8】JavaScript 基础语法入门(超全!!!) 一、JavaScript 简介二、引入 JavaScript 的三种方式三、变量与常量(var、let、const)3.1 var (传统方式ÿ…...
ppt流程图怎么?ppt流程图模板大全
ppt流程图怎么?ppt流程图剪头模板,ppt流程图模板大全: ppt流程图_模板素材_PPT模板_ppt素材_免抠图片_AiPPTer...
makefile总结
Makefile 学习视频:1、野火的基础入门篇-第32讲 Makefile三要素_哔哩哔哩_bilibili 2、b站视频04 一个稍复杂的Makefile_哔哩哔哩_bilibili 学习资料:第2个视频对应的Make/make.md 无限十三年/CPP - 码云 - 开源中国 ch0_Makefile简介 Makefile是什…...
MIME 类型是个什么东西?
MIME 类型(Multipurpose Internet Mail Extensions)即多用途互联网邮件扩展类型,它是一种标准,用于表示文档、文件或字节流的性质和格式。 最初设计用于电子邮件系统,后来被广泛应用于网页、HTTP 协议等领域࿰…...
javaWeb开发---前后端开发全景图解(基础梳理 + 技术体系)
在现代互联网开发中,前端与后端的分工协作非常重要。本文结合实际架构图,全面梳理前端技术栈、后端技术栈以及服务器端整体流程,帮助初学者建立清晰的整体认知。 一、整体架构概览 系统整体划分为三个主要部分: B端(…...
spring-rabbit的CachingConnectionFactory默认参数导致消费者Channel数量暴增问题解决
文章目录 1.前言2.解决2.1消费监听方法中关闭channel2.2 配置设置两个参数 3.总结 1.前言 由于之前写了一个好用的rabbitmq-spring-boot-start启动器,后面在生产实践之后反馈消费者连接的Channel数量过多,一个消费者的Channel数量可以达到好几百…...
线上JVM调优与全栈性能优化 - Java架构师面试实战
线上JVM调优与全栈性能优化 - Java架构师面试实战 本文通过一场互联网大厂的Java架构师面试,深入探讨了线上JVM调优、OOM定位、死锁定位、内存和CPU调优、线程池调优、数据库调优、缓存调优、网络调优、微服务调优及分布式调优等关键领域。 第一轮提问 面试官&am…...
【KWDB创作者计划】_企业级多模数据库实战:用KWDB实现时序+关系数据毫秒级融合(附代码、性能优化与架构图)
一、技术背景与行业痛点 1.1 多模数据融合挑战 场景痛点: 工业物联网设备每秒产生百万级传感器数据(时序数据)。需关联设备档案(关系数据)生成设备健康报告,传统方案需多数据库跳转,延迟>5…...
“八股训练营”学习总结
在参加为期 40 天的八股训练营的这段时间里,我收获满满,不仅在知识技能上得到了提升,更在学习习惯和自我认知方面有了很大的进步。 在知识层面,训练营涵盖了网络、数据库、缓存以及python测试开发等多方面的知识点。 网络方面&a…...
java工具类
LocalDateTime LocalDateTime可以获取当前时间: LocalDateTime now LocalDateTime.now(); 同时他也可以获取指定时间: LocalDateTime dateTime LocalDateTime.of(2023, 5, 15, 10, 30) 若我们时间值超出了我们的实际情况值,我们将会出现…...
「OC」源码学习——alloc与init的实现
「OC」源码学习——alloc与init的实现 前言 费劲千辛万苦终于项目给写完了,进入下一个阶段,源码的学习 alloc的调用顺序 我们在main函数之中打上断点,先运行 再在alloc之中的各个函数之中打上断点,在关键步骤上打上断点&#…...
AOSP Android14 Launcher3——动画核心类QuickstepTransitionManager详解
Launcher3中,有一个类在跟桌面相关的各种动画中扮演着非常关键的角色,这个类就是QuickstepTransitionManager。 QuickstepTransitionManager在aosp中的路径为:aosp/packages/apps/Launcher3/quickstep/src/com/android/launcher3/QuickstepT…...
STM32:看门狗
独立看门狗 简介 独立看门狗(IWDG)由独立的低速时钟(LSI)驱动,即便主时钟发生故障,它依然能够正常工作。其主要作用是在程序出现异常时,通过复位来保障系统的稳定性。独立看门狗的喂狗操作相对…...
第十三步:vue
Vue 1、上手 1、安装 使用命令:npm create vuelatestvue文件后缀为.vueconst app createApp(App):初始化根组件app.mount("#app"):挂载根组件到页面 2、文件 script标签:编写jstemplate标签:编写htmls…...
《代码整洁之道》第8章 边界 - 笔记
甚至是你团队里其他组写的你无法随意修改的代码。 这些外部代码是你的**“边界”。它们可能会升级、可能会有 Bug、可能会有反人类的设计、甚至你将来可能想换一个类似的库或服务。如果你的应用代码直接且紧密地依赖**这些外部代码的具体类、方法、异常等细节,那么…...
【CF】Day45——Codeforces Round 1021 (Div. 2) BC
阅读理解。。。不过挺有意思( B. Sasha and the Apartment Purchase 题目: 思路: 看了半天没看懂... 题目叽里咕噜一大堆,说白了就是让我们在一个 可删除k个数 的 数组 中选 一些点 且 这些点的f(x) 是此时 删完了k个数之后的数组…...
《代码整洁之道》第5章 格式 - 笔记
你应该选择一套管理代码格式的简单规则。如果是团队,应该选择一套团队一致同意采用的简单格式规则。 最重要的原则:一致性(Consistency)! 没有完美的格式规范,但有统一的规范。 整个团队(或者…...
通过示例学习:连续 XOR
通过示例学习:连续 XOR 如果我们想在 PyTorch 中构建神经网络,可以使用 (with) 指定所有参数(权重矩阵、偏差向量),让 PyTorch 计算梯度,然后调整参数。但是,如果我们有很…...
加密算法 AES、RSA、MD5、SM2 的对比分析与案例(AI)
加密算法 AES、RSA、MD5、SM2 的对比分析 一、相同点 密码学基础 均为现代密码学核心算法,用于保障数据安全。数据处理 均涉及数据转换(加密、签名、哈希等)。密钥依赖 AES、RSA、SM2 依赖密钥(对称或非对称&#x…...
基于STM32、HAL库的MAX31865模数转换器ADC驱动程序设计
一、简介: MAX31865是一款高精度的铂电阻温度检测器(RTD)至数字转换器,具有以下特点: 支持2线、3线或4线RTD配置 15位ADC分辨率 可编程RTD和基准电阻 内置故障检测(开路、短路等) SPI接口通信 工作电压:3.0V至3.6V 二、硬件接口: STM32L4XX <--> MAX31865 PA5(SCK…...
Laravel5.7的一些用法
1、事件需要运行 php artisan queue:work 2、数据库对象关联 1对1 hasOne 1对多 hasMany 1依赖多 belongsTo 多依赖多 belongsToMany 3、 关联查询 with 关联统计 withCount 统计时指定字段名。 如: withCount([cardHolderOrders as order_count]); 4、 // 一次查询&…...
Vue3 + OpenLayers 开发教程 (六)WebGL渲染优化
1. WebGL 渲染优化 1.1 WebGL 渲染器配置 创建 src/utils/webgl.ts: import { Map } from ol; import { WebGLPointsLayer } from ol/layer; import { Vector as VectorSource } from ol/source; import { Style, Circle, Fill, Stroke } from ol/style;// 创建 …...
【C++】C++11新特性(一)
文章目录 列表初始化initializer_list左值引用和右值引用 列表初始化 在 C98 中可以使用{}对数组或者结构体元素进行统一的列表初始值设定 struct Point {int _x;int _y; }; int main() {int array1[] { 1, 2, 3, 4, 5 };int array2[5] { 0 };Point p { 1, 2 };return 0; …...
【网络原理】 网络编程套接字
文章目录 一、网络编程基础1. 为什么需要网络编程?2. 什么是网络编程3 .网络编程中的基本概念发送端和接收端请求和响应客户端和服务端 4. 常见的客户端服务端模型 二、Socket套接字1. 概念2.分类3. Java数据报套接字通信模型4.Java流套接字通信模型 三、UDP数据报套…...
每天五分钟深度学习框架pytorch:使用visdom绘制损失函数图像
visdom的安装 pip install visdom如果安装失败 pip install --upgrade visdom开启visdom python -m visdom.server nohup python -m visdom.server后台启动然后就会出现,下面的页面,我们可以使用下面的链接打开visdom页面 Visdom中有两个重要概念: env环境。不同环境的可…...