代码改变世界

C++中的RAII技法

2016-08-22 16:58  shuaihanhungry  阅读(1184)  评论(0编辑  收藏  举报

Resource Acquisition Is Initialization or RAII, is a C++ programming technique which binds the life cycle of a resource (allocated memory, thread of execution, open socket, open file, locked mutex, database connection—anything that exists in limited supply) to the lifetime of an object.

所谓资源就是,一旦用了它,将来必须还给系统。如果不这样,糟糕的事情就会发生。常见的资源包括内存、文件描述符、互斥锁、数据库连接、网络sockets。

以对象管理资源的两个关键想法:获得资源后立刻放进管理对象;管理对象运用析构函数确保资源被释放。

对于heap-based资源,常被使的RAII classes分别是shared_ptrauto_ptr,有时可考虑boost::shared_arrayboost::scoped_array

对于非heap-based资源,常使用RAII手法封装资源的取得与释放,这时需要考虑RAII对象被复制,常见的行为是禁制复制、施行引用计数法并指定删除器、使用深度拷贝复制底部资源、转移底部资源的拥有权。

对于以上两种资源都需要考虑RAII对象析构时抛出异常的问题。

示例代码如下。

#include <mutex>
#include <iostream>
#include <string> 
#include <fstream>
#include <stdexcept>

void write_to_file (const std::string & message) {
    // mutex to protect file access (shared across threads)
    static std::mutex mutex;

    // lock mutex before accessing file
    std::lock_guard<std::mutex> lock(mutex);

    // try to open file
    std::ofstream file("example.txt");
    if (!file.is_open())
        throw std::runtime_error("unable to open file");
    
    // write message to file
    file << message << std::endl;
    
    // file will be closed 1st when leaving scope (regardless of exception)
    // mutex will be unlocked 2nd (from lock destructor) when leaving
    // scope (regardless of exception)
}

参考:《Effective C++》、wikipediacppreference