什么是资源获取初始化(RAII)?


当前回答

An object's lifetime is determined by its scope. However, sometimes we need, or it is useful, to create an object that lives independently of the scope where it was created. In C++, the operator new is used to create such an object. And to destroy the object, the operator delete can be used. Objects created by the operator new are dynamically allocated, i.e. allocated in dynamic memory (also called heap or free store). So, an object that was created by new will continue to exist until it's explicitly destroyed using delete.

使用new和delete时会出现以下错误:

泄漏对象(或内存):使用new分配对象,忘记删除对象。 过早删除(或悬空引用):持有指向对象的另一个指针,删除对象,然后使用另一个指针。 重复删除:尝试删除一个对象两次。

Generally, scoped variables are preferred. However, RAII can be used as an alternative to new and delete to make an object live independently of its scope. Such a technique consists of taking the pointer to the object that was allocated on the heap and placing it in a handle/manager object. The latter has a destructor that will take care of destroying the object. This will guarantee that the object is available to any function that wants access to it, and that the object is destroyed when the lifetime of the handle object ends, without the need for explicit cleanup.

c++标准库中使用RAII的例子有std::string和std::vector。

考虑下面这段代码:

void fn(const std::string& str)
{
    std::vector<char> vec;
    for (auto c : str)
        vec.push_back(c);
    // do something
}

当你创建一个向量并将元素推入它时,你不关心这些元素的分配和释放。vector使用new为其堆上的元素分配空间,并使用delete释放该空间。作为vector的用户,您不关心实现细节,并且相信vector不会泄漏。在本例中,vector是其元素的句柄对象。

其他使用RAII的标准库示例有std::shared_ptr、std::unique_ptr和std::lock_guard。

这种技术的另一个名称是SBRM,是作用域绑定资源管理(Scope-Bound Resource Management)的缩写。

其他回答

“RAII”代表“资源获取即初始化”,实际上是一个用词不当的词,因为它所关心的不是资源获取(和对象的初始化),而是释放资源(通过销毁对象)。 但RAII是我们得到的名字,并且一直沿用。

从本质上讲,这个习语的特点是将资源(内存块、打开的文件、解锁的互斥对象、you-name-it)封装在本地、自动对象中,并且当对象在其所属作用域的末尾被销毁时,该对象的析构函数会释放资源:

{
  raii obj(acquire_resource());
  // ...
} // obj's dtor will call release_resource()

当然,对象并不总是本地自动对象。他们也可以是一个阶级的成员:

class something {
private:
  raii obj_;  // will live and die with instances of the class
  // ... 
};

如果这样的对象管理内存,它们通常被称为“智能指针”。

There are many variations of this. For example, in the first code snippets the question arises what would happen if someone wanted to copy obj. The easiest way out would be to simply disallow copying. std::unique_ptr<>, a smart pointer to be part of the standard library as featured by the next C++ standard, does this. Another such smart pointer, std::shared_ptr features "shared ownership" of the resource (a dynamically allocated object) it holds. That is, it can freely be copied and all copies refer to the same object. The smart pointer keeps track of how many copies refer to the same object and will delete it when the last one is being destroyed. A third variant is featured by std::auto_ptr which implements a kind of move-semantics: An object is owned by only one pointer, and attempting to copy an object will result (through syntax hackery) in transferring ownership of the object to the target of the copy operation.

对于一个非常强大的概念来说,这是一个非常糟糕的名字,而且可能是c++开发人员在转向其他语言时最容易忽略的事情之一。有一些人试图将这个概念重命名为作用域绑定资源管理(Scope-Bound Resource Management),尽管它似乎还没有流行起来。

When we say 'Resource' we don't just mean memory - it could be file handles, network sockets, database handles, GDI objects... In short, things that we have a finite supply of and so we need to be able to control their usage. The 'Scope-bound' aspect means that the lifetime of the object is bound to the scope of a variable, so when the variable goes out of scope then the destructor will release the resource. A very useful property of this is that it makes for greater exception-safety. For instance, compare this:

RawResourceHandle* handle=createNewResource();
handle->performInvalidOperation();  // Oops, throws exception
...
deleteResource(handle); // oh dear, never gets called so the resource leaks

用RAII这个

class ManagedResourceHandle {
public:
   ManagedResourceHandle(RawResourceHandle* rawHandle_) : rawHandle(rawHandle_) {};
   ~ManagedResourceHandle() {delete rawHandle; }
   ... // omitted operator*, etc
private:
   RawResourceHandle* rawHandle;
};

ManagedResourceHandle handle(createNewResource());
handle->performInvalidOperation();

在后一种情况下,当抛出异常并展开堆栈时,局部变量将被销毁,这确保了我们的资源被清理并且不会泄漏。

RAII概念只是一个C堆栈变量的想法。最简单的解释。

An object's lifetime is determined by its scope. However, sometimes we need, or it is useful, to create an object that lives independently of the scope where it was created. In C++, the operator new is used to create such an object. And to destroy the object, the operator delete can be used. Objects created by the operator new are dynamically allocated, i.e. allocated in dynamic memory (also called heap or free store). So, an object that was created by new will continue to exist until it's explicitly destroyed using delete.

使用new和delete时会出现以下错误:

泄漏对象(或内存):使用new分配对象,忘记删除对象。 过早删除(或悬空引用):持有指向对象的另一个指针,删除对象,然后使用另一个指针。 重复删除:尝试删除一个对象两次。

Generally, scoped variables are preferred. However, RAII can be used as an alternative to new and delete to make an object live independently of its scope. Such a technique consists of taking the pointer to the object that was allocated on the heap and placing it in a handle/manager object. The latter has a destructor that will take care of destroying the object. This will guarantee that the object is available to any function that wants access to it, and that the object is destroyed when the lifetime of the handle object ends, without the need for explicit cleanup.

c++标准库中使用RAII的例子有std::string和std::vector。

考虑下面这段代码:

void fn(const std::string& str)
{
    std::vector<char> vec;
    for (auto c : str)
        vec.push_back(c);
    // do something
}

当你创建一个向量并将元素推入它时,你不关心这些元素的分配和释放。vector使用new为其堆上的元素分配空间,并使用delete释放该空间。作为vector的用户,您不关心实现细节,并且相信vector不会泄漏。在本例中,vector是其元素的句柄对象。

其他使用RAII的标准库示例有std::shared_ptr、std::unique_ptr和std::lock_guard。

这种技术的另一个名称是SBRM,是作用域绑定资源管理(Scope-Bound Resource Management)的缩写。

Manual memory management is a nightmare that programmers have been inventing ways to avoid since the invention of the compiler. Programming languages with garbage collectors make life easier, but at the cost of performance. In this article - Eliminating the Garbage Collector: The RAII Way, Toptal engineer Peter Goodspeed-Niklaus gives us a peek into the history of garbage collectors and explains how notions of ownership and borrowing can help eliminate garbage collectors without compromising their safety guarantees.