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


当前回答

《c++ Programming with Design Patterns Revealed》一书将RAII描述为:

获取所有资源 利用资源 释放资源

在哪里

资源被实现为类,所有指针都有类包装器(使它们成为智能指针)。 通过调用构造函数获取资源,通过调用析构函数隐式释放资源(与获取资源的顺序相反)。

其他回答

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

“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++ Programming with Design Patterns Revealed》一书将RAII描述为:

获取所有资源 利用资源 释放资源

在哪里

资源被实现为类,所有指针都有类包装器(使它们成为智能指针)。 通过调用构造函数获取资源,通过调用析构函数隐式释放资源(与获取资源的顺序相反)。

我已经多次回到这个问题并阅读了它,我认为投票最多的答案有点误导。

RAII的关键是:

“这(主要)不是关于捕捉异常,主要是关于管理资源的所有权。”

得票最高的答案夸大了例外安全,这让我很困惑。

事实是:

You still need to write try catch to handle exceptions (check the 2 code example below), except that you don't need to worry about releasing resources for those classes using RAII in your catch block. Otherwise, you need to look up each non-RAII class's API to find which function to call so as to release acquired resources in catch block. RAII simply save these work. Similar as above, when coding with RAII, you simply write less code, no need to call releasing resouce functions. All the clean-ups are done in the destructor.

另外,请查看我在上面的评论中发现的两个有用的代码示例。

https://ideone.com/1Jjzuc, https://ideone.com/xm2GR9

附言:我们可以用..来和蟒蛇比较。As语句,你也需要捕获可能发生在with块内部的异常。

许多人认为RAII是用词不当,但实际上它是这个习语的正确名称,只是没有很好地解释它。

Wikipedia explained behavior in detail: Resource acquisition is initialization (RAII) is a programming idiom used in several object-oriented, statically-typed programming languages to describe a particular language behavior. In RAII, holding a resource is a class invariant, and is tied to object lifetime: resource allocation (or acquisition) is done during object creation (specifically initialization), by the constructor, while resource deallocation (release) is done during object destruction (specifically finalization), by the destructor. In other words, resource acquisition must succeed for initialization to succeed. Thus the resource is guaranteed to be held between when initialization finishes and finalization starts (holding the resources is a class invariant), and to be held only when the object is alive. Thus if there are no object leaks, there are no resource leaks.

至于名称,它仅仅意味着“资源获取”操作是初始化操作,应该是资源类对象的初始化/构造函数的一部分。换句话说,使用这种习惯用法,使用资源意味着创建一个资源类来保存资源,并在构造类对象时初始化资源。它隐式地建议资源的释放应该在资源类析构函数中对称地发生。

这有什么用呢? 当然,您可以选择不使用这个成语,但是如果您想知道使用这个成语会得到什么,请考虑一下

RAII 对于更大的c++项目来说,在构造函数/析构函数对之外不包含对new或delete(或malloc/free)的单个调用是很常见的。或者实际上根本没有。

你可以避免

Exit: free_resource() //在退出函数前清除资源

或者使用RAII锁,这样你就不会忘记解锁。