Menu
CoddyTech

C++ 中的 RAII

本课属于 Coddy C++ 学习旅程的“面向对象编程”单元。第 16 课,共 104 课。

RAII(资源获取即初始化)是 C++ 中一种基本惯用法,它将资源管理与对象的生命周期绑定在一起。原理很简单:在构造函数中获取资源,在析构函数中释放资源。

创建对象时,它会获取所需的资源。对象超出作用域时,其析构函数会自动释放这些资源。即使发生异常,也能确保完成清理。

class FileHandler {
    std::FILE* file;
public:
    FileHandler(const char* filename) {
        file = std::fopen(filename, "r");  // 获取资源
    }
    
    ~FileHandler() {
        if (file) std::fclose(file);       // 释放资源
    }
};

使用 RAII,你不会忘记清理资源:

void processFile() {
    FileHandler handler("data.txt");  // 已获取资源
    // 处理文件……
    // 即使这里抛出异常,析构函数仍会运行!
}   // 资源自动释放

智能指针是 RAII 实际应用的绝佳例子。unique_ptr 在构造函数中获取堆内存的所有权,并在析构函数中删除它。你已经在使用 RAII 了,只是之前没有意识到!

RAII 适用于任何资源:内存、文件句柄、网络连接、互斥锁或数据库连接。通过将资源封装在对象中,C++ 可以确保进行确定性清理,并消除泄漏和悬空句柄等整类错误。

challenge icon

挑战

简单

让我们构建一个连接管理器,通过自动管理类似网络连接的生命周期来演示 RAII。创建连接时,它应该“打开”;连接超出作用域时,它应该自动“关闭”,无需手动清理!

你将创建两个文件来组织代码:

  • Connection.h:定义一个使用 RAII 原则管理连接资源的 Connection 类。这个类应包含:
    • 一个私有 connectionId 属性(字符串),用于标识连接
    • 一个私有 isOpen 属性(bool),用于跟踪连接状态
    • 一个接收连接 ID 的构造函数,将 isOpen 设为 true,并打印 "Opening connection: <id>"
    • 一个析构函数,检查连接是否处于打开状态,将 isOpen 设为 false 来关闭连接,并打印 "Closing connection: <id>"
    • 一个 send(string message) 方法,在连接处于打开状态时打印 "[<id>] Sending: <message>"
    • 一个返回连接 ID 的 getId() 方法
  • main.cpp:通过从输入中读取连接 ID 和消息,演示 RAII 如何确保自动清理。然后:
    • 使用花括号 { } 创建一个作用域
    • 在该作用域内,使用输入的 ID 在栈上创建一个 Connection 对象
    • 使用这个连接发送输入的消息
    • 让作用域结束(连接应自动关闭)
    • 在作用域结束后,打印 "Connection out of scope"

RAII 的优点在于,你不需要记得关闭连接:对象离开作用域时,析构函数会自动处理。这种模式可以防止资源泄漏,即使代码中发生意外情况也是如此。

在 main.cpp 中使用 #include "Connection.h" 引入头文件。

亲手试试

#include <iostream>
#include <string>
#include "Connection.h"

using namespace std;

int main() {
    string connectionId;
    string message;
    
    // 读取输入
    cin >> connectionId;
    cin.ignore();
    getline(cin, message);

    // TODO: 用花括号 { } 创建一个作用域
    // 在作用域内:
    //   - 用 connectionId 在栈上创建一个 Connection 对象
    //   - 使用连接发送消息
    // 让作用域结束(析构函数会自动调用)

    // TODO: 作用域结束后,输出 "Connection out of scope"

    return 0;
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: C++ 在线编译器