如何在第三方库代码中处理exit()调用?

时间:2013-01-07 16:11:42

标签: c++ legacy-code

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

我有应用程序和库的完整源代码,但是库已经非常完善并且没有单元测试,因此更改它将是一个大问题。有没有办法“挂钩”exit()的调用,以便我可以为我的应用程序实现正常关闭?

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

有没有一种已知的好方法可以解决这个问题?

4 个答案:

答案 0 :(得分:14)

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

由于您拥有库源,因此更容易 - 只需在构建时添加-Dexit=myExit标志,然后提供myExit的实现。

答案 1 :(得分:4)

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

答案 2 :(得分:2)

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

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

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

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

答案 3 :(得分:1)

如果来电exit而不是assertabort,则有几点可以再次获得控制权:

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

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