资源获取的含义是初始化(RAII)?

资源获取的含义是初始化(RAII)?

对于一个非常强大的概念来说,这真是一个非常糟糕的名字,也许是C ++开发人员在切换到其他语言时想念的第一件事情之一。 试图将这个概念重新命名为“ 范围绑定资源pipe理” ,虽然似乎还没有被发现,但还是有一些动作。

当我们说'资源'时,我们不只是指记忆 – 它可以是文件句柄,networking套接字,数据库句柄,GDI对象…总之,我们有一个有限的供应,所以我们需要能够控制他们的使用。 “范围绑定”方面意味着对象的生命周期被绑定到variables的范围,所以当variables超出范围时,析构函数将释放资源。 这是一个非常有用的特性,它使得更大的exception安全性。 比如,比较一下:

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(); 

在后一种情况下,抛出exception并解开堆栈时,局部variables将被销毁,从而确保我们的资源被清理并不会泄漏。

这是一个简单的意思是你的编程习惯用法

  • 将一个资源封装到一个类(其构造函数通常(但不一定是**)获取资源,并且其析构函数总是释放它)
  • 通过类的本地实例使用资源*
  • 当对象超出范围时资源会自动释放

这保证了无论在资源使用时发生什么,它最终都会被释放(无论是由于正常返回,包含对象的销毁还是抛出的exception)。

这是C ++中广泛使用的良好实践,因为除了处理资源的安全方式之外,它还使代码更加清洁,因为您不需要将error handling代码与主要function混合在一起。

* 更新: “本地”可能意味着一个局部variables,或一个类的非静态成员variables。 在后一种情况下,成员variables被初始化并被其所有者对象销毁。

** Update2:正如@sbi所指出的那样,资源 – 尽pipe经常在构造函数中分配 – 也可以在外部分配并作为参数传入。

“RAII”代表“资源获取是初始化”,实际上相当不恰当,因为它并不涉及资源获取 (和对象的初始化),而是释放资源(通过销毁对象)。
但RAII是我们得到的名字,它坚持。

它的核心就是在本地自动化对象中封装资源(内存块,打开文件,解锁互斥体,you-name-it),并在该对象被销毁时释放资源的析构函数所属范围的结尾:

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

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

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

如果这些对象pipe理内存,他们通常被称为“智能指针”。

这有很多变化。 例如,在第一个代码片段中,如果有人想复制obj会出现什么情况。 最简单的方法是简单地禁止复制。 std::unique_ptr<> ,这是一个智能指针,作为下一个C ++标准所std::unique_ptr<>的标准库的一部分。
另一个这样的智能指针, std::shared_ptr具有资源(一个dynamic分配的对象)的“共享所有权”。 也就是说,它可以被自由地复制,并且所有的副本都指向同一个对象。 智能指针会logging多less个副本引用同一个对象,并在最后一个被销毁时将其删除。
std::auto_ptr实现了第三种变体,它实现了一种移动语义:一个对象只有一个指针,并且试图复制对象将导致(通过语法hackery)将对象的所有权转移到目标的复制操作。

“ C ++ Programming with Design Patterns Revealed ”一书将RAII描述为:

  1. 获取所有资源
  2. 使用资源
  3. 释放资源

哪里

  • 资源是以类的forms实现的,所有的指针都有类包装(使它们成为智能指针)。

  • 资源是通过调用它们的构造函数获得的,并通过调用它们的析构函数来隐式释放(以获取的相反顺序)。

手动内存pipe理是编程人员从发明编译器以来一直在发明的避免方法的噩梦。 编程语言与垃圾收集器使生活更容易,但代价是性能。 在本文“ 消除垃圾收集者:RAII之路”中 ,Toptal工程师Peter Goodspeed-Niklaus向我们介绍了垃圾收集者的历史,并解释了所有权和借款的概念如何帮助消除垃圾收集者,同时又不损害他们的安全保证。