the*_*ill 337
对于一个非常强大的概念来说,这是一个非常糟糕的名字,也许是C++开发人员在切换到其他语言时所遗漏的第一件事.试图将这个概念重命名为Scope-Bound Resource Management有一点动作,尽管它似乎还没有流行起来.
当我们说'资源'时,我们不仅仅意味着内存 - 它可能是文件句柄,网络套接字,数据库句柄,GDI对象......简而言之,我们有限供应的东西,所以我们需要能够控制他们的用法."范围限制"方面意味着对象的生命周期绑定到变量的范围,因此当变量超出范围时,析构函数将释放资源.一个非常有用的特性是它可以提高安全性.例如,比较一下:
RawResourceHandle* handle=createNewResource();
handle->performInvalidOperation(); // Oops, throws exception
...
deleteResource(handle); // oh dear, never gets called so the resource leaks
Run Code Online (Sandbox Code Playgroud)
与RAII一起
class ManagedResourceHandle {
public:
ManagedResourceHandle(RawResourceHandle* rawHandle_) : rawHandle(rawHandle_) {};
~ManagedResourceHandle() {delete rawHandle; }
... // omitted operator*, etc
private:
RawResourceHandle* rawHandle;
};
ManagedResourceHandle handle(createNewResource());
handle->performInvalidOperation();
Run Code Online (Sandbox Code Playgroud)
在后一种情况下,当抛出异常并且堆栈被展开时,局部变量被破坏,这确保我们的资源被清理并且不会泄漏.
Pét*_*rök 117
这是一个简单的意思是你的编程习语
这保证了在资源正在使用时发生的任何事情,它最终都会被释放(无论是由于正常返回,包含对象的破坏还是抛出异常).
它是C++中广泛使用的良好实践,因为除了是一种处理资源的安全方式之外,它还使您的代码更加清晰,因为您不需要将错误处理代码与主要功能混合在一起.
*
更新: "local"可能表示本地变量或类的非静态成员变量.在后一种情况下,使用其所有者对象初始化和销毁成员变量.
**
Update2:正如@sbi指出的那样,资源 - 虽然经常在构造函数内部分配 - 也可以在外部分配并作为参数传入.
sbi*_*sbi 46
"RAII"代表"资源获取是初始化",实际上是一个误称,因为它不关心资源获取(和对象的初始化),而是释放资源(通过破坏对象) ).
但RAII是我们得到的名字,它坚持.
这个成语的核心功能是在本地自动对象中封装资源(内存块,打开文件,解锁的互斥体,你自己的名字),并在对象被销毁时释放该对象的析构函数.它所属范围的结尾:
{
raii obj(acquire_resource());
// ...
} // obj's dtor will call release_resource()
Run Code Online (Sandbox Code Playgroud)
当然,对象并不总是本地的自动对象.他们也可以成为一个班级的成员:
class something {
private:
raii obj_; // will live and die with instances of the class
// ...
};
Run Code Online (Sandbox Code Playgroud)
如果这些对象管理内存,它们通常被称为"智能指针".
这有很多变化.例如,在第一个代码片段中,问题出现了如果有人想要复制会发生什么obj
.最简单的方法是简单地禁止复制.std::unique_ptr<>
,一个智能指针,作为下一个C++标准所特有的标准库的一部分,就是这样做的.
另一个这样的智能指针,std::shared_ptr
具有它所拥有的资源(动态分配的对象)的"共享所有权".也就是说,它可以自由复制,所有副本都可以引用同一个对象.智能指针跟踪多少个副本引用同一个对象,并在最后一个副本被销毁时删除它.
第三种变体的特点是std::auto_ptr
它实现了一种移动语义:一个对象只有一个指针,并且尝试复制一个对象将导致(通过语法hackery)将对象的所有权转移到复制操作的目标.
Den*_*nis 12
" C++ Programming with Design Patterns Revealed "一书将RAII描述为:
哪里
资源是作为类实现的,并且所有指针都有围绕它们的类包装器(使它们成为智能指针).
通过调用其构造函数获取资源,并通过调用其析构函数隐式地(以获取的相反顺序)释放资源.
elm*_*mar 11
对象的生存期由其范围决定。但是,有时我们需要创建一个对象,该对象与创建对象的作用域无关,这是有用的,或者很有用。在C ++中,运算符new
用于创建这样的对象。为了销毁该物体,delete
可以使用操作员。由操作员创建的对象new
是动态分配的,即在动态内存(也称为堆或自由存储)中分配。因此,由创建的对象new
将继续存在,直到使用明确销毁为止delete
。
使用new
和时可能发生的一些错误delete
是:
new
用于分配对象并忘记delete
该对象。delete
,然后再使用另一个指针。delete
一个对象两次。通常,范围变量是首选。然而,RAII可以用作替代new
和delete
使对象活独立地是对其范围的。这种技术包括将指针分配到在堆上分配的对象,并将其放置在handle / manager对象中。后者具有一个析构函数,将负责销毁该对象。这将确保该对象可用于任何想要访问它的函数,并且该对象在句柄对象的生存期结束时将被销毁,而无需进行显式清理。
来自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
}
Run Code Online (Sandbox Code Playgroud)
当创建向量并将元素推入向量时,您不必担心分配和取消分配此类元素。向量用于new
在堆上为其元素分配空间,并delete
释放该空间。作为vector的用户,您无需关心实现细节,并且会相信vector不会泄漏。在这种情况下,向量是其元素的句柄对象。
标准库中的其他例子是使用RAII是std::shared_ptr
,std::unique_ptr
和std::lock_guard
。
该技术的另一个名称是SBRM,是范围绑定资源管理的缩写。
自从编译器问世以来,手工内存管理是程序员一直在想办法避免的噩梦。使用垃圾回收器进行编程的语言可以使生活更轻松,但是会降低性能。在本文“ 消除垃圾收集器:RAII方式”中,Toptal工程师Peter Goodspeed-Niklaus向我们介绍了垃圾收集器的历史,并解释了所有权和借用的概念如何在不损害其安全保证的前提下帮助消除垃圾收集器。
小智 5
RAII类分为三个部分:
RAII代表“资源获取是初始化”。RAII的“资源获取”部分是您开始某些必须在以后结束的事情的地方,例如:
“初始化”部分意味着获取发生在类的构造函数内部。