RAII理解 - 访问有界指针的方法

时间:2014-03-05 08:02:42

标签: c++ raii

我正在阅读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的公开方法了吗?自this link以来我有点困惑,the_mandrill的答案没有解释这种情况

所以这可以用作

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

2 个答案:

答案 0 :(得分:1)

首先,存在(广泛的)混淆,所以让我清楚一点。


RAII代表资源获取是初始化。这里关注的是类不变量之一,并且将资源的获取与对象的构造联系起来意味着:每当你对这样一个对象有句柄时,就是由资源支持

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

但是,由于典型的RAII容器在销毁时也会负责释放资源,因此RAII通常通俗地用于指代适当的资源管理。这超出了它的范围,并且容器如:

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

    Handle& handle;
};

对资源管理没有任何作用仍然是RAII容器,因为它保证了资源的存在。

已经尝试过其他缩略语来表达对资源的适当管理,例如SBRM:范围限制资源管理,但他们没有采取(在SBRM情况下,它没有考虑到资源不一定与一个词汇范围)。


您的界面需要注意。

在C时代,有一种智慧表明,任何分配资源(通常是记忆)的人也应该提供一种解除分配方法。这确保了资源被正确释放,因为只有其创建者知道它是如何分配的。即使在今天,它仍然是一个很好的建议。

然而,您的界面存在不对称性:您传递指针并在其上调用delete。但是,如果它是一个指向数组的指针呢?如果是堆栈对象怎么办?致电delete是荒谬的。


对您的实施提出警告。

我希望你这是一个精心裁剪的例子,但是因为它们缺失了我不禁提醒你应该遵循Rule of Three(在C +中使它成为 Five 11)。

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


回到你的问题:一般来说,你需要一种方法来访问底层资源,否则它将毫无用处。

但有多种方法:

  • 如果您的容器是专用的,它可能会呈现面向域的接口,这就是fstream所做的例子:您不访问FILE*或其他任何内容,而是使用{{1 }}和<<以及>>等等。
  • 您可以返回句柄(指针或引用)
  • 你可能有一个带有仿函数的方法,并会通过对象的引用来调用它(更多功能导向,在C ++中更少见)

由您来设计界面,以便您的客户可以实际使用该资源。

答案 1 :(得分:0)

C ++没有try-finally结构,RAII基本上是使用C ++工具集对finally块进行模拟(好吧,也许比这更多但是如果你知道尝试的话,这很容易理解-最后)。您使用析构函数编写一个类,并在堆栈上按值实例化此类。当这个实例用完作用域时,无论你如何离开作用域,它的析构函数都会被执行(返回,异常,中断,继续......)。这个析构函数执行可以被视为“finally”块,因此您可以将资源的清理放入析构函数中,以确保资源在范围的末尾不会泄漏(在本例中为您的foo *)。在C ++中还有一些特殊的作用域(当你通过值定义基于RAII的类的实例作为另一个对象的一部分时 - 那么你的RAII对象的范围是它的容器对象的生命周期,这不适合于try-finally示例......)

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