我正在阅读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();
答案 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 }}和<<
以及>>
等等。由您来设计界面,以便您的客户可以实际使用该资源。
答案 1 :(得分:0)
C ++没有try-finally结构,RAII基本上是使用C ++工具集对finally块进行模拟(好吧,也许比这更多但是如果你知道尝试的话,这很容易理解-最后)。您使用析构函数编写一个类,并在堆栈上按值实例化此类。当这个实例用完作用域时,无论你如何离开作用域,它的析构函数都会被执行(返回,异常,中断,继续......)。这个析构函数执行可以被视为“finally”块,因此您可以将资源的清理放入析构函数中,以确保资源在范围的末尾不会泄漏(在本例中为您的foo *)。在C ++中还有一些特殊的作用域(当你通过值定义基于RAII的类的实例作为另一个对象的一部分时 - 那么你的RAII对象的范围是它的容器对象的生命周期,这不适合于try-finally示例......)
只有当你理解了来自其他语言的try-finally块的概念时,这个解释当然对你有意义... Visual C ++也有一个非标准的__finally处理程序(基于SEH),我不知道它是否仍然存在有这个。