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

RAII(Resource Acquisition Is Initialization)机制

RAII(Resource Acquisition Is Initialization)机制

1. 什么是 RAII?

🌟 RAII(资源获取即初始化,Resource Acquisition Is Initialization)C++ 语言中的一种管理资源的编程技巧
RAII 使资源(如内存、文件句柄、线程、锁等)与对象的生命周期绑定
这意味着:

  • 对象构造时(constructor)申请资源
  • 对象析构时(destructor)自动释放资源

2. RAII 解决了什么问题?

RAII 解决了 手动管理资源 的各种问题,例如:

  • 忘记释放资源(导致内存泄漏文件句柄泄漏
  • 异常导致资源释放失败(如果函数 throw 异常,资源可能不会被释放)
  • 资源管理逻辑分散,代码难以维护

RAII 确保资源不会泄漏,并且异常不会破坏资源管理,从而 提高代码的安全性和可维护性


3. RAII 代码示例

RAII 典型的做法是:使用类的构造函数获取资源,使用析构函数释放资源

🔥 示例 1:FILE 文件句柄管理(避免 fopen() 忘记 fclose()

#include <iostream>
#include <cstdio>class FileHandler {
public:explicit FileHandler(const char* filename) {file_ = std::fopen(filename, "w");if (!file_) {throw std::runtime_error("无法打开文件!");}}~FileHandler() {  // RAII: 在析构函数中释放资源if (file_) {std::fclose(file_); std::cout << "文件已关闭\n";}}void write(const char* text) {if (file_) {std::fprintf(file_, "%s", text);}}private:FILE* file_; // 资源:文件指针
};int main() {try {FileHandler fh("example.txt");  // 构造时打开文件fh.write("Hello, RAII!\n");} catch (const std::exception& e) {std::cerr << "异常:" << e.what() << std::endl;} // FileHandler 对象 `fh` 作用域结束后,自动释放文件资源
}

📌 这里的 RAII 机制:

  • 构造函数 (FileHandler::FileHandler()) 申请 fopen() 资源
  • 析构函数 (FileHandler::~FileHandler()) 释放 fclose() 资源
  • 即使异常发生,析构函数依旧会执行,确保不会忘记释放资源

🔥 示例 2:智能指针(避免 new 后忘记 delete
在 C++98 及之前,动态分配对象需要手动使用 new/delete

void bad_example() {int* p = new int(10); // 申请内存throw std::runtime_error("发生异常!"); // Oops! `delete p;` 没有执行,内存泄漏!delete p; // 永远不会执行
}

RAII 解决这个问题,C++11 以后我们可以使用 std::unique_ptr

#include <memory>
void good_example() {std::unique_ptr<int> p = std::make_unique<int>(10); // RAII:构造时申请资源throw std::runtime_error("发生异常!"); // 资源仍然会被自动释放,不会泄漏!
} // 作用域结束,自动调用 `unique_ptr` 析构函数,释放 `int*`

📌 这里的 RAII 机制:

  • std::unique_ptr<int> 绑定了 new int(10) 的生命周期
  • 异常发生时,unique_ptr 自动释放 int*,不会导致内存泄漏

🔥 示例 3:C++ std::lock_guard 保护互斥锁
手动加锁和解锁,非常容易遗漏:

std::mutex mtx;
void bad_function() {mtx.lock();  // 手动加锁throw std::runtime_error("发生异常!");  // Oops! 没有 `unlock()`,死锁风险!mtx.unlock();
}

RAII 方式(使用 std::lock_guard):

#include <iostream>
#include <mutex>
#include <thread>std::mutex mtx;void safe_function() {std::lock_guard<std::mutex> guard(mtx); // RAII:构造时加锁,析构时自动解锁std::cout << "安全访问共享资源\n";// 作用域结束 `lock_guard` 析构时,自动解锁,避免死锁风险
}

4. LoanedCommandInterface 是如何使用 RAII 的?

ROS 2 hardware_interface::LoanedCommandInterface 也是 RAII 设计模式 的一个典型应用:

class LoanedCommandInterface {
public:explicit LoanedCommandInterface(CommandInterface* cmd): command_interface_(cmd) {}~LoanedCommandInterface() { command_interface_ = nullptr; } // RAII 释放资源double get_value() { return command_interface_->get_value(); }void set_value(double value) { command_interface_->set_value(value); }private:CommandInterface* command_interface_;
};

📌 RAII 这里的作用:

  • 构造函数 LoanedCommandInterface() 申请硬件接口
  • 析构函数 ~LoanedCommandInterface() 自动释放硬件接口
  • 即使异常发生,析构仍然会执行,防止资源泄漏

5. 什么时候使用 RAII?

✅ 当你需要手动管理资源(如 内存、文件、锁、网络连接、数据库连接)时,尽量使用 RAII:

  • 替代 new/delete —— 使用 std::unique_ptr
  • 替代 malloc/free —— 使用 std::vector(内部自动管理 new[]/delete[]
  • 处理文件 —— 用 std::fstream,避免 fopen/fclose
  • 管理线程同步 —— 用 std::lock_guard 自动管理 std::mutex

6. RAII 适用于 C++,但在 C 语言中常见吗?

C 语言本身 不支持 RAII,因为 C 没有构造函数/析构函数,必须手动释放资源:

FILE* file = fopen("data.txt", "w");
if (!file) { return -1; }
// 使用文件...
fclose(file);  // 记得手动释放资源

在 C++ 里,我们可以使用 RAII 方式,减少手动释放资源的风险

std::ofstream file("data.txt");

文件会在 std::ofstream 对象销毁时 自动关闭,避免了 C 语言里可能出现的 资源泄漏


7. 总结

🔹 RAII(资源获取即初始化)是 C++ 的重要设计模式
🔹 在构造函数获取资源,在析构函数释放资源,防止泄漏
🔹 RAII 适用于内存(智能指针)、文件、锁、线程、数据库连接等
🔹 std::unique_ptrstd::vectorstd::lock_guard 都是 RAII 典型应用
🔹 hardware_interface::LoanedCommandInterface 也是基于 RAII 的设计

🚀 RAII 增强代码的安全性、可维护性,尽量在 C++ 编程中使用 RAII! 🚀


http://www.mrgr.cn/news/90703.html

相关文章:

  • Unity UI 道路线跟随:让图标沿道路轨迹移动
  • VUE 解决若依出现Error: Cannot find module ‘@/views/xxx‘问题
  • 好好说话:深度学习扫盲
  • Android车机DIY开发之软件篇(十二) AOSP12下载编译
  • 解决Blender无法识别Num关闭状态下的笔记本数字键盘中Home键、End键问题
  • DeepSeek 本地部署指南
  • Kotlin 2.1.0 入门教程(十七)接口
  • DeepSeek预测2025目标检测算法Top 5:谁将主导下一代视觉感知?
  • 多媒体软件安全与授权新范例,用 CodeMeter 实现安全、高效的软件许可管理
  • 机器学习-1:线性回归
  • java处理pgsql的text[]类型数据问题
  • 运维-自动访问系统并截图
  • 「软件设计模式」工厂方法模式 vs 抽象工厂模式
  • 【Unity Shader编程】之顶点着色器
  • 「软件设计模式」单例模式
  • linux的三剑客和进程处理
  • 200个Python练手项目源码
  • rocketmq-netty通信设计-request和response
  • 【DeepSeek】Deepseek辅组编程-通过卫星轨道计算终端距离、相对速度和多普勒频移
  • 【Stable Diffusion部署至GNU/Linux】安装流程
  • Ubuntu启动geteck/jetlinks实战:Docker启动
  • Proxmox VE 8.3 qm 方式导入ESXi Linux OVA UEFI模式虚拟机
  • C++类和对象进阶:运算符重载深度详解
  • 在vscode中拉取gitee里的项目并运行
  • Python----PyQt开发(PyQt高级:手搓一个文件浏览器)
  • Druid GetConnectionTimeoutException解决方案之一