惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
小众软件
小众软件
WordPress大学
WordPress大学
Microsoft Azure Blog
Microsoft Azure Blog
Recent Announcements
Recent Announcements
博客园 - 三生石上(FineUI控件)
博客园_首页
N
Netflix TechBlog - Medium
IT之家
IT之家
H
Help Net Security
博客园 - 聂微东
Google DeepMind News
Google DeepMind News
罗磊的独立博客
T
Tailwind CSS Blog
F
Fortinet All Blogs
Hugging Face - Blog
Hugging Face - Blog
MongoDB | Blog
MongoDB | Blog
V
V2EX
量子位
云风的 BLOG
云风的 BLOG
爱范儿
爱范儿
博客园 - 司徒正美
The Cloudflare Blog
Engineering at Meta
Engineering at Meta

博客园 - 平凡人

std::atomic linux学习-目录 C++设计模式--PIMPL C++技术之---标准容器的值语义 blender学习系列之--CLOG Blender中的DNA QT元对象系统(Meta-Object System) Blender文档翻译:ID Datablocks(ID数据块) Blender内存管理库(bf_intern_guardedalloc) IDA\Windbg调试 - 平凡人 - 博客园 IOCTL(CTL_CODE) 内核开发速查表 Blender中的事件处理器 Blender:SDNA QT信号和槽 利用QEventLoop实现同步等待信号槽返回结果 Blender文档翻译:Operators tutorial(操作教程) Blender文档翻译:Operators Blender文档翻译:RNA Blender文档翻译-Blender库数据的通用属性
c++的RAII
平凡人 · 2026-01-29 · via 博客园 - 平凡人

RAII(资源获取即初始化)

RAII(Resource Acquisition Is Initialization)是C++的核心编程理念,将资源的生命周期与对象的生命周期绑定,确保资源在对象构造时获取,在对象析构时释放。

核心思想

基本模式

class ResourceHolder {
private:
    Resource* res;  // 资源句柄
    
public:
    // 获取资源
    ResourceHolder() : res(new Resource()) {
        // 资源已初始化
    }
    
    // 释放资源
    ~ResourceHolder() {
        delete res;
    }
    
    // 禁止拷贝(或实现移动语义)
    ResourceHolder(const ResourceHolder&) = delete;
    ResourceHolder& operator=(const ResourceHolder&) = delete;
};

现代C++中的RAII应用

1. 智能指针(最典型的RAII应用)

#include <memory>

void modern_raii_example() {
    // 自动管理内存
    auto ptr = std::make_unique<int>(42);  // 构造时获取
    // 离开作用域时自动释放
    
    // 共享所有权
    auto shared = std::make_shared<MyClass>();
    
    // 弱引用
    std::weak_ptr<MyClass> weak = shared;
}

2. 容器类

#include <vector>
#include <string>

void container_example() {
    std::vector<std::string> strings = {"RAII", "is", "awesome"};
    // vector析构时自动释放所有元素的内存
    
    std::map<int, std::unique_ptr<Resource>> resources;
    // map析构时自动释放所有资源
}

3. 文件操作

#include <fstream>

void file_example() {
    {
        std::ofstream file("data.txt");  // 打开文件
        file << "Hello RAII";            // 使用文件
    } // 离开作用域,自动关闭文件
    
    // 无需显式调用 file.close()
}

4. 锁管理

#include <mutex>

std::mutex mtx;

void thread_safe_function() {
    std::lock_guard<std::mutex> lock(mtx);  // 获取锁
    // 临界区操作
    // 离开作用域时自动释放锁
    
    // C++17更灵活
    std::scoped_lock lock2(mtx);  // 可管理多个锁
}

5. 自定义RAII类

class DatabaseConnection {
private:
    DatabaseHandle* handle;
    
public:
    // 构造时连接
    DatabaseConnection(const std::string& conn_str) 
        : handle(connect_to_database(conn_str)) {
        if (!handle) throw std::runtime_error("连接失败");
    }
    
    // 析构时断开
    ~DatabaseConnection() {
        if (handle) disconnect(handle);
    }
    
    // 支持移动语义
    DatabaseConnection(DatabaseConnection&& other) noexcept
        : handle(other.handle) {
        other.handle = nullptr;
    }
    
    DatabaseConnection& operator=(DatabaseConnection&& other) noexcept {
        if (this != &other) {
            if (handle) disconnect(handle);
            handle = other.handle;
            other.handle = nullptr;
        }
        return *this;
    }
    
    // 禁止拷贝
    DatabaseConnection(const DatabaseConnection&) = delete;
    DatabaseConnection& operator=(const DatabaseConnection&) = delete;
};

现代C++的最佳实践

1. 使用智能指针而非裸指针

// 不好
void legacy_style() {
    Resource* res = new Resource();
    // ... 可能忘记delete
}

// 好
void modern_style() {
    auto res = std::make_unique<Resource>();
    // 自动管理生命周期
}

2. 利用作用域控制资源

void scope_based_management() {
    {
        auto resource = acquire_resource();
        // 使用resource
    } // resource在此处自动释放
    
    // 更安全:异常安全
    auto resource = acquire_resource();
    std::shared_ptr<void> cleanup(nullptr, 
        [&](void*) { release_resource(resource); });
}

3. 结合异常安全

class Transaction {
private:
    Database& db;
    
public:
    explicit Transaction(Database& db) : db(db) {
        db.begin_transaction();
    }
    
    ~Transaction() {
        if (std::uncaught_exceptions() > 0) {
            db.rollback();  // 发生异常时回滚
        } else {
            db.commit();    // 正常结束时提交
        }
    }
    
    // 使用示例
    void transfer_funds() {
        Transaction trans(db);  // 开始事务
        db.withdraw(account1, 100);
        db.deposit(account2, 100);
        // 离开作用域时自动提交或回滚
    }
};

4. 使用RAII包装C接口

class CFileWrapper {
private:
    FILE* file;
    
public:
    CFileWrapper(const char* filename, const char* mode) 
        : file(fopen(filename, mode)) {
        if (!file) throw std::runtime_error("无法打开文件");
    }
    
    ~CFileWrapper() {
        if (file) fclose(file);
    }
    
    // 使用移动语义
    CFileWrapper(CFileWrapper&& other) noexcept : file(other.file) {
        other.file = nullptr;
    }
    
    FILE* get() const { return file; }
    
    // 使用示例
    void process_file() {
        CFileWrapper file("data.bin", "rb");
        // 使用file.get()操作
        // 自动关闭
    }
};

RAII的优势

  1. 异常安全:即使抛出异常,资源也能正确释放
  2. 避免泄漏:自动管理生命周期,无忘记释放的风险
  3. 代码简洁:减少try-catch和清理代码
  4. 确定性销毁:C++保证析构函数在作用域退出时被调用
  5. 可组合性:RAII对象可以包含其他RAII对象

总结

现代C++中,RAII已不仅仅是内存管理,而是所有资源管理的标准范式:

  • 内存 → 智能指针(unique_ptr, shared_ptr
  • 文件/网络 → 流类(ifstream, ofstream
  • lock_guard, unique_lock
  • 其他资源 → 自定义RAII包装器

RAII体现了C++的零开销抽象原则:资源管理自动化的同时,不带来运行时开销。这是编写安全、高效、易维护C++代码的基石。