问题标签 [raii]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
3 回答
906 浏览

perl - 如何在 Perl 中自动释放资源 RAII 样式?

假设我有一个必须释放的资源(例如文件句柄或网络套接字):

假设那process可能会死。然后代码块提前退出,并且$fh不会关闭。

我可以明确检查错误:

但是众所周知,这种代码很难正确编写,并且只会在添加更多资源时变得更加复杂。

在 C++ 中,我将使用RAII创建一个拥有资源的对象,并且其析构函数将释放它。这样,我就不必记住释放资源,并且只要 RAII 对象超出范围,资源清理就会正确进行——即使抛出异常也是如此。不幸的是,在 Perl 中,一个DESTROY方法不适合此目的,因为无法保证何时调用它。

是否有一种 Perlish 方法可以确保即使在存在异常的情况下也能像这样自动释放资源?还是显式错误检查是唯一的选择?

0 投票
4 回答
2448 浏览

.net - 当本机 (C++) 异常传播到 CLR 组件时未调用析构函数

我们有大量的本地 C++ 代码,编译成 DLL。

然后我们有几个包含 C++/CLI 代理代码的 dll 来包装 C++ 接口。

最重要的是,我们将 C# 代码调用到 C++/CLI 包装器中。

标准的东西,到目前为止。

但是我们有很多情况允许本地 C++ 异常传播到 .Net 世界,我们依靠 .Net 将它们包装为 System.Exception 对象的能力,并且在大多数情况下这工作正常。

然而,我们发现当异常传播时,抛出点范围内的对象的析构函数没有被调用!

经过一些研究,我们发现这是一个众所周知的问题。然而,解决方案/解决方法似乎不太一致。我们确实发现,如果使用 /EHa 而不是 /EHsc 编译本机代码,问题就会消失(至少在我们的测试用例中是这样)。然而,我们更喜欢使用 /EHsc,因为我们自己将 SEH 异常转换为 C++ 异常,并且我们宁愿让编译器有更多的优化空间。

这个问题还有其他解决方法吗 - 除了将每个调用都包装在(本机)try-catch-throw 中(除了 C++/CLI 层)之外?

0 投票
4 回答
396 浏览

c++ - 让析构函数根据是否发生异常采取不同的操作

我有一些代码来更新看起来像的数据库表

我想将事务逻辑包装在 RAII 类中,这样我就可以编写

但是我将如何为它编写析构函数呢?

0 投票
4 回答
23828 浏览

c++ - C++ 的 RAII 教程

我想学习如何在 C++ 中使用 RAII。我想我知道它是什么,但不知道如何在我的程序中实现它。快速的谷歌搜索没有显示任何好的教程。

有没有人有任何很好的链接来教我 RAII?

0 投票
7 回答
741 浏览

c++ - 为 RAII 模板类编写对象生成器的更好方法?

我想为模板化的 RAII 类编写一个对象生成器——基本上是一个函数模板,用于使用参数的类型推导构造一个对象,因此不必明确指定类型。

我预见的问题是,为我处理类型推导的辅助函数将按值返回对象,这将 (**) 导致在复制时过早调用 RAII 析构函数。也许 C++0x 移动语义会有所帮助,但这对我来说不是一个选择。

有人以前见过这个问题并有好的解决方案吗?

这就是我所拥有的:

要点是它OtherThing有一个可怕的界面,并且FooAdder应该使它更易于使用。预期用途大致是这样的:

构造FooAdder函数初始化一些内部数据结构。foobar方法填充这些数据结构。~FooAdderdtor 将事情包装起来并调用 on 方法thing_,处理所有的麻烦。

FooAdder如果不是模板,那会很好用。但既然是这样,我需要把类型放进去,更像这样:

这很烦人,因为类型可以基于myThing. 所以我更愿意创建一个模板化的对象生成器,类似于std::make_pair,它将为我进行类型推导。像这样的东西:

这似乎有问题:因为它按值返回,堆栈临时对象将 (**) 被破坏,这将导致 RAII dtor 过早运行。

** - 如果未实施 RVO。大多数编译器都这样做,但这不是必需的,可以在 gcc 中使用-fno-elide-constructors.

0 投票
6 回答
2882 浏览

c++ - 如何处理未能释放包含在智能指针中的资源?

当表示资源的对象包含在共享指针中时,应如何处理资源释放期间的错误?

编辑1:

用更具体的术语来说明这个问题:许多 C 风格的接口具有分配资源和释放资源的功能。示例是用于 POSIX 系统上的文件描述符的 open(2) 和 close(2),用于连接到 X 服务器的 XOpenDisplay 和 XCloseDisplay,或用于连接到 SQLite 数据库的 sqlite3_open 和 sqlite3_close。

我喜欢将此类接口封装在 C++ 类中,使用 Pimpl 习惯用法隐藏实现细节,并提供返回共享指针的工厂方法,以确保在没有对资源的引用时释放资源。

但是,在上面给出的所有示例和许多其他示例中,用于释放资源的函数可能会报告错误。如果这个函数被析构函数调用,我不能抛出异常,因为通常析构函数不能抛出。

另一方面,如果我提供了一个公共方法来释放资源,那么我现在有一个具有两种可能状态的类:一种是资源有效,另一种是资源已被释放。这不仅使类的实现复杂化,而且还存在错误使用的可能性。这很糟糕,因为接口应该旨在使使用错误成为不可能。

对于这个问题的任何帮助,我将不胜感激。

问题的原始陈述以及关于可能解决方案的想法如下。

编辑2:

现在有一个赏金这个问题。解决方案必须满足以下要求:

  1. 当且仅当没有对它的引用时才释放该资源。
  2. 对资源的引用可能会被显式销毁。如果在释放资源时发生错误,则会引发异常。
  3. 不能使用已经释放的资源。
  4. 资源的引用计数和释放是线程安全的

解决方案满足以下要求:

  1. 它使用boost提供的共享指针、C++ Technical Report 1 (TR1)和即将推出的 C++ 标准C++0x
  2. 它是通用的。资源类只需要实现资源的释放方式即可。

感谢您的时间和想法。

编辑 3:

感谢所有回答我问题的人。

Alsk 的回答满足了赏金中的所有要求,并被接受。在多线程代码中,此解决方案将需要一个单独的清理线程。

我添加了另一个答案,其中清理期间的任何异常都由实际使用资源的线程引发,而无需单独的清理线程。如果您仍然对这个问题感兴趣(它困扰了我很多),请发表评论。

智能指针是安全管理资源的有用工具。此类资源的示例是内存、磁盘文件、数据库连接或网络连接。

在典型的场景中,封装资源的类应该是不可复制的和多态的。支持这一点的一个好方法是提供一个返回共享指针的工厂方法,并将所有构造函数声明为非公共的。共享指针现在可以自由复制和分配。当没有对它的引用时,该对象将自动销毁,然后析构函数释放资源。

但是这种方法存在一个问题。析构函数不能抛出,因此释放资源的失败将不会被检测到。

解决这个问题的一个常见方法是添加一个公共方法来释放资源。

不幸的是,这种方法引入了另一个问题:我们的对象现在可能包含已经释放的资源。这使资源类的实现复杂化。更糟糕的是,它使该类的客户可能错误地使用它。以下示例可能看起来有些牵强,但它是多线程代码中的常见缺陷。

要么我们确保在对象被销毁之前不释放资源,从而失去任何处理失败资源释放的方法。或者我们提供了一种在对象生命周期内显式释放资源的方法,从而可以错误地使用资源类。

有办法摆脱这种困境。但解决方案涉及使用修改后的共享指针类。这些修改可能会引起争议。

典型的共享指针实现,例如 boost::shared_ptr,要求在调用其对象的析构函数时不抛出异常。通常,任何析构函数都不应该抛出,所以这是一个合理的要求。这些实现还允许指定自定义删除函数,当没有对对象的引用时调用该函数以代替析构函数。不抛出要求扩展到此自定义删除器功能。

这个要求的基本原理很清楚:共享指针的析构函数不能抛出。如果删除函数不抛出,共享指针的析构函数也不会抛出。然而,对于导致资源释放的共享指针的其他成员函数也是如此,例如reset():如果资源释放失败,则不会抛出异常。

这里提出的解决方案是允许自定义删除函数抛出。这意味着修改后的共享指针的析构函数必须捕获删除函数抛出的异常。另一方面,除析构函数之外的成员函数,例如reset(),不应捕获删除函数的异常(并且它们的实现变得更加复杂)。

这是原始示例,使用抛出删除器函数:

我们现在可以使用 reset() 显式释放资源。如果在另一个线程或程序的另一部分中仍然存在对该资源的引用,则调用 reset() 只会减少引用计数。如果这是对该资源的最后一次引用,则释放该资源。如果资源释放失败,则会引发异常。

编辑:

这是删除器的完整(但依赖于平台)实现:

0 投票
3 回答
235 浏览

java - ~1s 延迟控制应用程序:这适用于 Java 吗?

在我的工作中,我们最近完成了一个控制应用程序的系统架构,该应用程序的最大延迟大约为一到两秒。它分布在通过 IP LAN 通信的小型 ARM 片上盒上。

我们最初预计我们将使用 C 或 C++,因为它是一种经典的控制系统语言。在讨论了如何实现应用程序之后,我们现在意识到 C++ 的库数量非常有限,缺乏自省,并且还有一些其他属性可能会减慢开发速度。然后我的同事建议 Java 可能胜任这项工作。

我真的很害怕为控制应用程序运行 GC 的延迟,而且我也不愿意放弃 RAII,因为该应用程序将使用大量外部资源(套接字、文件句柄、来自外部库的句柄等)。

目前的优缺点列表如下:

这篇 AMD 文章中提到了并行 GC 的内存碎片

如果 GC 延迟不是问题并且我们可以获得 RAII,我很乐意使用 Java。因此,我还研究了其他具有 RAII 并且可以作为很好的替代品的语言,到目前为止,我发现 D、Ada、VB、Perl、Python(C)、PHP、tcl 和 Lua 似乎有某种超出范围的回调。我的自发反应也许 D、Python 和 ADA 可能适用于控制应用程序。D 和 ADA 是我的最爱。

所以,我的问题是:你对此有什么建议吗?Java 是一个可行的选择吗?如果你可以选择任何一种语言,你会选择什么?

0 投票
2 回答
562 浏览

c++ - 在 CTOR 和智能指针中抛出异常

是否可以在我的构造函数中使用以下代码将 XML 文档加载到成员变量中 - 如果有任何问题,则抛出给调用者:

基于更有效的 C++ 中的 Scott Myers RAII 实现,如果他分配任何资源(即指针),他会进行清理:

我相信我可以在使用智能指针(IXMLDOMDocumentPtr)时允许从 CTOR 抛出异常。

让我知道你的想法....

0 投票
1 回答
465 浏览

c++ - 如何混合 TDD 和 RAII

我正在尝试为我的新项目进行广泛的测试,但我遇到了问题。

基本上我想测试 MyClass。MyClass 使用了其他几个我不需要/不想为测试目的完成工作的课程。所以我创建了模拟(我使用 gtest 和 gmock 进行测试)

但是 MyClass 在它的构造函数中实例化它需要的一切,并在析构函数中释放它。我认为这就是RAII。

所以我想,我应该创建某种工厂,它创建所有内容并将其提供给 MyClass 的构造函数。那家工厂可能有假货用于测试目的。但那不再是 RAII 了吗?

那么这里有什么好的解决方案?

0 投票
5 回答
2690 浏览

c++ - 让 shared_ptr 在其引用计数达到 0 时调用成员函数

我正在为不能与 DuplicateHandle 一起使用的 HANDLE 创建一个包装器,因此我试图将句柄包装在 shared_ptr 中。

想象一下下面的代码:

我还尝试使用 HANDLE 参数创建关闭(不理想)。无论哪种方式,我都会收到编译器错误“术语不会评估为采用 0 个参数的函数”。这是因为隐含的 this 指针吗?我该如何解决?如何从共享指针调用成员函数?