lock_guard是RAII实现还是用于实现RAII

Is lock_guard a RAII implementation or it is used to implement RAII?

本文关键字:实现 RAII 用于 guard lock      更新时间:2023-10-16

维基百科(和其他一些来源)声明:

在RAII中,持有资源与对象生命周期相关联:资源分配(获取)是在对象创建(特别是初始化)期间由构造函数完成的,而资源释放(释放)是在对象销毁期间由析构函数完成的。如果对象被正确地析构,就不会发生资源泄漏。

但是,wiki上的例子显示的代码根本没有显示对象的构造函数/析构函数:

#include <string>
#include <mutex>
#include <iostream>
#include <fstream>
#include <stdexcept>
void write_to_file (const std::string & message) {
    // mutex to protect file access
    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)
}

我找到的lock_guard的定义也引用了它是"RAII-style":

lock_guard类是一个互斥锁包装器,它提供了一种方便的raii风格机制,用于在一个作用域块的持续时间内拥有一个互斥锁。

在这个例子中,RAII是在互斥锁类上实现的,还是在lock_guard类中实现的?或者根本没有在类上实现?

RAII是c++中构造函数和析构函数的一种用法,用于确保成功的获取操作不会被撤销。典型的例子是锁的获取和释放。

class mutex_guard {
public:
    explicit mutex_guard(mutex& lock): m_lock(lock) {
       m_lock.acquire();
    }
    ~mutex_guard() { m_lock.release(); }
private:
   mutex& m_lock;
};

当创建mutex_guard的实例时,它会获取锁或者失败(如果mutex::acquire抛出)。如果成功,则完全实例化guard对象,并保证调用它的析构函数。因此,如果互斥锁被成功获取,则保证了对mutex::release的调用。

规范的实现是保证一个完全构造的对象在离开作用域时总是被销毁,以确保获得的资源总是被释放。从这个意义上说,它使用对象和实例生命周期的标准保证来实现RAII习惯用法的需求。

这是lock_guard谁提供RAII 同步在你发布的片段。mutex本身不遵循RAII习惯用法。RAII不必由单独的对象提供。例如,std::ofstream为文件输出操作提供了功能,而RAII 为文件状态openclose 提供了功能。这是留给设计师的自由吗?

RAII = Resource Acquisition Is Initialization

ie对象创建意味着资源获取,对象销毁意味着资源销毁。如果您在其他地方进行获取或销毁,那么您就没有使用RAII。

可以在RAII中使用对象的构造函数和析构函数。事实上,这是习语最常见的用法之一。例如,一个非常非常简单的智能指针(可能是RAII的典型例子)可以像下面这样实现(live on ideone):

#include <iostream>
template<typename T>
class RAIIpointer
{
private:
    T* _raw_pointer;
public:
    explicit RAIIpointer(T* managed): _raw_pointer(managed)  // acquiring resource
    {
        std::cout << "ttAllocating memory for single objectn";
    }
    ~RAIIpointer() // releasing resource
    {
        std::cout << "ttReleasing memory for single objectn";
        delete _raw_pointer;
    }
};
template<typename T>
class RAIIpointer<T[]> // array specialization
{
private:
    T* _raw_pointer;
public:
    explicit RAIIpointer(T* managed): _raw_pointer(managed) // acquiring resource
    {
        std::cout << "ttAllocating memory for arrayn";
    }
    ~RAIIpointer() // releasing resource
    {
        std::cout << "ttReleasing memory for arrayn";
        delete[] _raw_pointer;
    }
};
int main()
{
    std::cout << "Before entering RAII scopen";
    {
        std::cout << "tCreating a smart pointer...n";
        RAIIpointer<int> smart_ptr(new int); // that's it, automatic release when scope ends
        RAIIpointer<int[]> smart_ptr_arr(new int[42]); // same
        std::cout << "tDone with itn";
    }
    std::cout << "After exiting RAII scopen";
}

你可以在这里清楚地看到tor和dtor是如何执行分配/释放的。它对客户端是完全透明的(这里是主要功能)。这正是std::lock_guard背后的思想:它的构造函数获取std::mutex,当对象超出作用域时,它的析构函数释放它。