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

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

Wikipedia(以及其他一些来源)指出:

In RAII, holding a resource is tied to object lifetime: resource allocation (acquisition) is done during object creation (specifically initialization), by the constructor, while resource deallocation (release) is done during object destruction, by the destructor. If objects are destructed properly, resource leaks do not occur.

但是,wiki 上的示例显示的代码根本没有向我们显示对象的 constructos/desctructors:

#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":

The class lock_guard is a mutex wrapper that provides a convenient RAII-style mechanism for owning a mutex for the duration of a scoped block.

在示例中,RAII 是在互斥量 class 上实现的,还是在 lock_guard class?或者根本没有在 class 上实现?

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 抛出)。如果它确实成功了,守卫对象将被完全实例化,并且保证调用它的析构函数。因此,如果互斥锁获取成功,则对mutex::release的调用是有保证的。

规范实现使用保证完全构造的对象在离开作用域时始终被销毁以确保始终释放获取的资源。从这个意义上讲,它使用对象和实例生命周期的标准保证来实现 RAII 惯用语的要求。

lock_guard 提供了 RAII 同步 在您发布的片段中。 mutex 本身不遵循 RAII 习语。 RAII 不必由单独的对象提供。例如,std::ofstream 提供文件输出操作的功能和 RAII 文件状态 open\close。是不是留给设计师的自由。

RAII = Resource Acquisition Is Initialization

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

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

#include <iostream>

template<typename T>
class RAIIpointer
{
private:
    T* _raw_pointer;
public:
    explicit RAIIpointer(T* managed): _raw_pointer(managed)  // acquiring resource
    {
        std::cout << "\t\tAllocating memory for single object\n";
    }
    ~RAIIpointer() // releasing resource
    {
        std::cout << "\t\tReleasing memory for single object\n";
        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 << "\t\tAllocating memory for array\n";
    }
    ~RAIIpointer() // releasing resource
    {
        std::cout << "\t\tReleasing memory for array\n";
        delete[] _raw_pointer;
    }
};

int main()
{
    std::cout << "Before entering RAII scope\n";
    {
        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 it\n";
    }
    std::cout << "After exiting RAII scope\n";
}

你可以在这里清楚地看到ctor和dtor是如何执行allocation/deallocation的。它对客户端是完全透明的(这里是主要功能)。这正是 std::lock_guard 背后的想法:它的构造函数获取一个 std::mutex,它的析构函数在对象超出范围时释放它。