|
|
1
331
RAII的一个简单(可能使用过度)示例是File类。如果没有RAII,代码可能如下所示:
换句话说,我们必须确保在完成文件后关闭它。这有两个缺点——首先,无论我们在哪里使用File,我们都必须调用File::close()——如果我们忘记了这样做,那么我们保存文件的时间会比需要的时间长。第二个问题是,如果在我们关闭文件之前抛出异常会怎么样? Java使用finally子句解决了第二个问题:
或者从Java 7开始,使用try with resource语句:
在Java中无法做到这一点,因为无法保证对象何时被销毁,因此我们无法保证诸如文件之类的资源何时被释放。 在智能指针上——很多时候,我们只是在堆栈上创建对象。例如(从另一个答案中窃取一个例子):
这很好,但是如果我们想返回str呢?我们可以这样写:
不幸的是,这段代码不起作用。我们将返回一个指向str的指针-但是str是在堆栈上创建的,因此一旦退出foo(),就会被删除。换句话说,当调用者得到指针时,它是无用的(而且可以说比无用还要糟糕,因为使用它可能会导致各种各样的可怕错误) 那么,解决方案是什么?我们可以使用new在堆上创建str,这样,当foo()完成时,str就不会被销毁。
当然,这个解决方案也不是完美的。原因是我们创建了str,但从未删除它。在一个非常小的程序中,这可能不是问题,但一般来说,我们希望确保删除它。我们可以说调用方必须在完成对象后删除它。缺点是调用者必须管理内存,这增加了额外的复杂性,并且可能会出错,导致内存泄漏,即即使不再需要对象,也不能删除对象。
现在有两个对同一字符串的引用。一旦没有剩余的str引用,它将被删除。因此,您不再需要担心自己删除它。 快速编辑:正如一些评论所指出的,这个例子并不完美,至少有两个原因。首先,由于字符串的实现,复制字符串的成本往往较低。其次,由于所谓的返回值优化,按值返回可能并不昂贵,因为编译器可以做一些聪明的事情来加快速度。
假设我们想使用一个文件作为日志。这意味着我们希望以仅附加模式打开文件:
现在,让我们将文件设置为其他两个对象的日志:
不幸的是,这个例子结束得很糟糕——这个方法一结束,这个文件就会被关闭,这意味着foo和bar现在有一个无效的日志文件。我们可以在堆上构造文件,并将指向文件的指针传递给foo和bar:
但谁负责删除文件呢?如果两个文件都没有删除,那么内存和资源都会泄漏。我们不知道foo或bar是否会首先处理完该文件,因此我们也不能期望它们自己删除该文件。例如,如果foo在bar完成之前删除了该文件,则bar现在有一个无效指针。
现在,没有人需要担心删除文件-一旦foo和bar都完成了,并且不再有任何对文件的引用(可能是因为foo和bar被销毁),文件将自动删除。 |
|
2
144
拉伊 对于一个简单但令人敬畏的概念来说,这是一个奇怪的名字。名字更好 范围限制资源管理 仅举一个不使用SBRM的示例:
正如你所看到的,我们有很多方法可以解决问题。我们的想法是将资源管理封装到一个类中。其对象的初始化获取资源(“资源获取即初始化”)。当我们退出块(块范围)时,资源再次被释放。
如果您有自己的类,而这些类不仅仅是为了分配/释放资源,那就很好了。分配只是完成工作的另一个问题。但是,只要您只想分配/取消分配资源,上述情况就会变得不好处理。您必须为获得的每种资源编写一个包装类。为了简化这一过程,智能指针允许您自动化该过程:
通常情况下,智能指针是围绕new/delete的薄型包装,刚好调用
unique_ptr是专门拥有对象的智能指针。它不是在Boost中,但它可能会出现在下一个C++标准中。它是 不可复制 所有权转让 . 一些示例代码(下一个C++):
与auto_ptr不同,unique_ptr可以放在容器中,因为容器可以保存不可复制(但可移动)的类型,比如streams和unique_ptr。
scoped_ptr代码:
shared_ptr是为了共享所有权。因此,它既可复制又可移动。多个智能指针实例可以拥有相同的资源。一旦拥有资源的最后一个智能指针超出范围,资源将被释放。我的一个项目的一些现实例子:
如您所见,打印源(函数fx)是共享的,但每个源都有一个单独的条目,我们在该条目上设置颜色。当代码需要引用智能指针所拥有的资源,但不需要拥有该资源时,可以使用弱_ptr类。然后,您应该创建弱\u ptr,而不是传递原始指针。当它注意到您试图通过弱\u ptr访问路径访问资源时,它将引发异常,即使不再有共享\u ptr拥有该资源。 |
|
3
32
其前提和理由在概念上很简单。RAII是确保 这将所有初始化和清理简化为一个步骤。 C++不需要RAII,但是越来越多地接受使用RAII方法将产生更健壮的代码。
通过将所有初始化和清理绑定到这些机制,确保C++将为您处理这项工作。
|
|
|
4
8
智能指针是RAII的变体。RAII意味着资源获取是初始化。智能指针在使用前获取资源(内存),然后在析构函数中自动将其丢弃。发生了两件事:
例如,另一个例子是网络套接字RAII。在这种情况下:
智能指针的C++源在网络上的数百万人,包括我上面的回答。 |
|
|
5
2
Boost有很多这样的功能,包括
Boost.Interprocess
用于共享内存。它极大地简化了内存管理,特别是在令人头痛的情况下,例如当您有5个进程共享相同的数据结构时:当每个人都使用完一块内存时,您希望它自动释放&不必坐在那里试图找出谁应该负责打电话
|
|
|
6
0
void foo()
{
std::string bar;
//
// more code here
//
}
不管发生什么情况,一旦foo()函数的作用域被留下,bar将被正确删除。 在内部std::string实现通常使用引用计数指针。因此,仅当字符串的一个副本发生更改时,才需要复制内部字符串。因此,引用计数智能指针可以仅在必要时复制某些内容。
|