RAII理解-有界指针的重音方法

RAII understanding - Accesing methods of a bounded pointer

本文关键字:方法 指针 理解 RAII      更新时间:2023-10-16

我读到了关于RAII概念的文章,在试图理解它的同时,我制定了以下示例。

class foo_handler
{
private:
foo* f;
public:
foo_handler(foo* inc) : f(inc){}
~foo_handler(){delete f;}
};

我的问题是,假设foo有一个名为SomeMethod的方法,那么foo_handler不需要有一个具有以下签名的方法吗

foo* returnFoo();

以便我们可以访问foo的公开方法?我在这里有点困惑,因为这个链接,the_mandrill的答案并没有解释这种情况

所以这可以用作

foo_handler d;
d.returnFoo()->SomeMethod();

首先,有一个(广泛的)混淆,让我来澄清一下。


RAII代表资源获取即初始化。这里关注的是类不变量之一,将资源的获取与对象的构造联系起来意味着:无论何时,只要您有这样一个对象的句柄,它都由资源支持。

或者换句话说,如果获取资源失败,那么对象永远不会诞生(它的构造函数中止/shops/anthe)。

然而,由于RAII容器通常也会负责销毁后释放资源,因此RAII通常被通俗地用来指代适当的资源管理。不过,这超出了它的范围,而且像这样的容器

struct RaiiHandle {
RaiiHandle(Handle& h): handle(h) {}
Handle& handle;
};

对资源管理不做任何事情的RAII容器仍然是RAII容器,因为它保证了资源的存在。

其他缩写词也试图表达对资源的正确管理,如SBRM:范围限制资源管理,但它们没有考虑(在SBRM的情况下,它没有考虑到资源不一定与词汇范围相关的事实)。


在您的界面上要注意一点。

在C时代,有一条智慧说,无论谁分配了一个资源(通常是内存),都应该提供一种解除分配的方法。这确保了资源被正确地解除分配,因为只有它的创建者知道它是如何分配的。即使在今天,它仍然是一个很好的建议。

然而,你的接口存在不对称性:你被传递了一个指针,并在上面调用delete。但如果它是一个指向数组的指针呢?如果它是一个堆栈对象呢?调用delete是荒谬的。


请注意您的实现。

为了你的利益,我希望这是一个精简的例子,但由于它们不见了,我不得不提醒你应该遵循三条规则(在C++11中使其Five)。

永远不要忘记的一个非常简单的方法是更改unique_ptr的原始指针(可能使用自定义的deleter)。默认情况下,它将具有正确的移动成员,并将强制您在需要时编写复制成员。


回到您的问题:通常,您需要一种访问底层资源的方法,否则它将毫无用处。

不过有多种方法:

  • 如果你的容器是专用的,它可能会呈现一个面向域的接口,例如fstream就是这样做的:你不访问FILE*或里面的任何东西,而是使用<<>>.eof()
  • 您可以返回句柄(指针或引用)
  • 您可能有一个方法,它接受一个函子,并通过对对象的引用来调用它(更倾向于函数,在C++中不太常见)

由您设计接口,以便您的客户端可以实际使用资源。

C++没有try-filly构造,RAII基本上是用C++工具集模拟finally块(好吧,可能不止于此,但如果你知道try-filly,用这种方式理解它很容易)。使用析构函数编写一个类,然后通过堆栈上的值实例化这个类。当这个实例超出作用域时,无论你如何离开作用域,它的析构函数都会被执行(带有return、exception、break、continue…)。这个析构函数的执行可以被视为"finally"块,所以你可以将资源的清理放在析构函数中,以确保资源不会在作用域的末尾泄漏(在这种情况下,你的foo*)。在C++中也有一些特殊的作用域(当你通过值将基于RAII的类的实例定义为另一个对象的一部分时,那么你的RAII对象的作用域就是它的容器对象的生存期,这与try finally示例不符…)

当然,只有当你理解了其他语言中try finally块的概念时,这个解释才对你有意义。。。Visual C++也有一个非标准的__finally处理程序(基于SEH),我不知道它是否还有这个。