12

我正在开发一个 C++ 应用程序,它使用另一个团队用 C 语言编写的库。库的编写者喜欢exit()在发生错误时调用,这会立即结束程序,而无需调用 C++ 应用程序中堆栈上的对象的析构函数。应用程序设置了一些在进程结束后不会被操作系统自动回收的系统资源(共享内存区域、进程间互斥体等),所以这是一个问题。

我有完整的应用程序和库的源代码,但是库非常完善并且没有单元测试,所以改变它会很重要。有没有办法“挂钩”调用,exit()以便我可以为我的应用程序实现正常关闭?

我正在考虑的一种可能性是创建一个大类,应用程序——这意味着所有清理都将发生在其析构函数或其中一个成员的析构函数中——然后在堆中分配这些大对象之一main(),设置一个全局指向它的指针,并使用atexit()来注册一个处理程序,该处理程序只是通过全局指针删除对象。这可能行得通吗?

有没有已知的好方法来解决这个问题?

4

4 回答 4

14

在最坏的情况下,您始终可以编写自己的实现exit并链接它,而不是系统自己的实现。您可以在那里处理错误,也可以选择给_exit(2)自己打电话。

由于您拥有库源代码,因此更容易 - 只需-Dexit=myExit在构建时添加一个标志,然后提供myExit.

于 2013-01-07T16:14:34.120 回答
4

使用atexit安装退出处理程序并实现所需的行为

于 2013-01-07T16:16:39.347 回答
2

如果您想让 C 库在 C++ 中更有用,您也许可以在单独的进程中运行它。然后确保(使用退出处理程序或其他方式)当它退出时,您的主应用程序进程会注意到并抛出异常以展开它自己的堆栈。也许在某些情况下,它可以以非致命的方式处理错误。

当然,将库使用转移到另一个进程可能并不容易或特别有效。您需要做一些工作来包装接口,并通过您选择的 IPC 机制复制输入和输出。

但是,作为从主进程使用库的一种解决方法,我认为您描述的那个应该可以工作。风险在于您无法识别和隔离需要清理的所有内容,或者假设堆栈将正常展开,将来有人会修改您的应用程序(或您使用的其他组件)。

可以修改库源以调用运行时或编译时可配置函数,而不是调用exit(). 然后编译带有异常处理的库并在 C++ 中实现该函数以引发异常。这样做的问题是库本身可能会在错误时泄漏资源,因此您必须使用该异常来展开堆栈(并且可能会进行一些错误报告)。即使就您的应用而言,错误可能不是致命的,也不要抓住它并继续。

于 2013-01-07T16:27:19.763 回答
1

如果 callexit和 not assertor abort,有几点可以再次控制:

  • 调用 时exit,具有静态生命周期的对象的析构函数(本质上是:全局变量和用 声明的对象static)仍会执行。这意味着您可以设置(少数)全局“资源管理器”对象并在其析构函数中释放资源。
  • 正如您已经发现的那样,您可以使用atexit. 这不限于一个。您可以注册更多。

如果一切都失败了,因为你有库的源代码,你可以玩一些宏技巧来有效地用exit你自己的函数替换调用,例如,抛出异常。

于 2013-01-07T16:52:23.830 回答