为旧C代码生成C ++ API的正确方法是什么?该代码广泛使用带有多个跳转目标的longjmp进行错误管理?
我的想法是编写一个函数来为每个使用过的目标设置跳转目标,例如:
void catchJumps() {
if (setjmp(target1)) throw Error1(); //Error1 and Error2 are some exception classes
if (setjmp(target2)) throw Error2();
//...
}
然后我在每个使用C代码的C ++函数(在每个范围内,更具体)中调用catchJumps
:
int some_wrapper() {
catchJumps();
callCFunction()
for (int i = 0; i < 1000; i++) {
catchJumps();
callOtherCFunction();
}
catchJumps();
callOneMoreCFunction();
callEvenOneMoreCFunction();
}
这是一种在不破坏堆栈的情况下捕获所有longjump的安全方法吗?我知道,longjmp进入不同的堆栈框架是危险的。现在,我的函数catchJumps
位于另一个堆栈帧中而不是调用some_wrapper
。我希望(或者我甚至可以做到)catchJumps可以内联,所以框架是相同的,但我不知道。
调用范围对象的所有析构函数时,每个范围(以及上面的循环之后)的调用都是必要的,对吗?
如果这不是将longjmps“转换”为调用应用程序断言的有效方法,我们还能做些什么呢?
答案 0 :(得分:3)
使用catchJumps
自动对象具有析构函数时可能会遇到问题,如https://stackoverflow.com/a/1376099/471164中所述并引用18.7 / 4“其他运行时支持”:
如果抛出的异常会破坏任何自动对象 将控制转移到程序中的另一个(目标)点, 然后在转移的投掷点调用longjmp(jbuf,val) 对同一(目标)点的控制具有未定义的行为。
我认为更好的方法是为您使用的每个C函数创建一个包装器,并且可以longjmp
将所有这些非本地的getos转换为异常。这也将使您的代码更清晰,因为您不会在所有地方都有catchJumps()
,而只是在这些包装函数中。
答案 1 :(得分:2)
由于您在库中遇到了这样的API,让catchJumps
通过要求传入零参数可调用并使用函数指针或boost/std::function
来执行实际调用?
template <typename CallMe>
void catchJumps(CallMe wrappee)
{
if (setjmp(target1)) throw Error1(); //Error1 and Error2 are some exception classes
if (setjmp(target2)) throw Error2();
//...
wrappee();
}
int some_wrapper()
{
catchJumps(&callCFunction);
for (int i = 0; i < 1000; i++)
{
catchJumps(&callOtherCFunction);
}
catchJumps(&callOneMoreCFunction);
catchJumps(&callEvenOneMoreCFunction);
}