从库中退出()可以替换为抛出异常吗?

时间:2015-05-13 16:17:02

标签: c++ c exception

我正在使用C ++的C / Fortran库,并且库调用exit()。我希望它抛出异常,以便调用我的C ++程序中的析构函数。我已经能够创建一个抛出异常的exit定义,但是仍然会调用terminate。是否可以防止终止被调用并允许正常的异常处理发生?

更新:在评论中指出,这适用于x64但在x86上失败,因此主要问题是"是否有办法使x86像x64一样工作?"。

UPDATE2:请参阅我的回复,了解为什么这不适用于x86以及如何解决它。

这是我的测试代码:

test_exception.c

#include <stdlib.h>

void call_c() { exit(1); }

test_exception.cpp

#include <iostream>
#include <stdexcept>

extern "C" void call_c();

extern "C" void exit(int value)
{
  throw std::runtime_error(std::string("Throwing an exception: ") + char('0' + value));
}

int main()
{
  try {
    call_c();
  } catch (const std::exception &e) {
    std::cerr << e.what() << std::endl;
    return 1;
  }

  return 0;
}

使用以下命令构建:

gcc -c test_exception.c -o test_exception_c.o
g++ -c test_exception.cpp -o test_exception_cpp.o
g++ test_exception_c.o test_exception_cpp.o -o test_exception

3 个答案:

答案 0 :(得分:2)

我知道您可能不想阅读此内容,但在任何部分尝试调用>sh run_script.sh 或类似内容后,继续执行程序很可能是错误的。

如果程序的一部分名为ImportError: No module named 'twitter' ,则您无法保证该程序的状态。您不知道堆是否处于一致状态。你不知道堆栈是否有用。如果您将exit()转换为exit(),则每次发生这种情况时,您可能遇到的非常内存泄漏最少。您不知道是否可以再次安全地调用导致此错误的库。

如果您已经检查了库的源代码,并且您确定不会导致损坏,那么最干净的解决方案是修改库本身,以便它抛出而不是退出。

如果不允许更改库,则另一个干净且正确的解决方案是将库的所有用法放入一个单独的进程中,您可以监视并重新启动。

答案 1 :(得分:1)

上面的代码可以工作,但是在g86 4.6之前的x86上,在构建C代码时需要添加-fexceptions或-funwind-tables,以便可以进行堆栈展开。您可以看到details here

答案 2 :(得分:0)

除非你的C ++实现被破坏,否则在调用exit时会调用全局变量的析构函数(GCC没有被破坏,至少我试过的所有版本都没有)。因此,您只需要清理那些不会被全局变量破坏者清理的东西。

对于堆上的全局内容,可以使用atexit注册一个在调用exit时调用的清理函数 - 这个清理函数可以delete任何堆对象需要清理。

堆栈上的东西的析构函数要复杂得多。最好的解决方案可能是确保不需要调用这样的析构函数 - 在退出之前必须清理的任何东西都应该由在析构函数中进行清理的全局(可能使用类的静态成员)引用。