C ++异常会通过C代码安全传播吗?

时间:2010-01-20 12:49:19

标签: c++ c exception visual-c++ exception-handling

我有一个调用SQLite的C ++应用程序(SQLite在C中)sqlite3_exec(),后者可以调用我在C ++中实现的回调函数。 SQLite被编译成静态库。

如果异常转义我的回调,它会通过SQLite的C代码安全地传播到调用sqlite3_exec()的C ++代码吗?

5 个答案:

答案 0 :(得分:29)

我的猜测是这取决于编译器。但是,在回调中抛出异常将是一个非常糟糕的主意。它要么完全不起作用,要么SQLite库中的C代码将无法处理它。考虑这是否是SQLite中的一些代码:

{
  char * p = malloc( 1000 );
  ...
  call_the_callback();  // might throw an exception
  ...
  free( p );
}

如果异常“有效”,则C代码无法捕获它,并且永远不会释放p。当然,库可能已分配的任何其他资源也是如此。

答案 1 :(得分:14)

已经有一个回调协议可以中止API调用。来自the docs

  

如果sqlite3_exec()回调返回   非零,sqlite3_exec()例程   返回SQLITE_ABORT而不调用   再次回调而不运行   任何后续的SQL语句。

我强烈建议您使用此而不是例外。

答案 2 :(得分:10)

SQLite希望您在出错时返回SQLITE_ABORT,并返回0返回代码,没有错误。因此,您应该将所有C ++回调包装在try catch 中。然后在catch中返回一个SQLite SQLITE_ABORT错误代码,否则为零。

如果你绕过通过SQLite返回会出现问题,因为它不会释放/完成从你的回调返回后它执行的任何代码。这将导致一些未解决的问题,其中一些问题可能非常模糊。

答案 3 :(得分:1)

这是一个非常有趣的问题,我出于好奇而自行测试。在我的OS X w / gcc 4.2.1上答案是肯定的。它完美地运作。我认为一个真正的测试是使用gcc用于C ++和其他一些(MSVC?,LLVM?)用于C部分,看它是否仍然有用。

我的代码:

callb.h:

#ifdef __cplusplus
extern "C" {
#endif

typedef void (*t_callb)();
void cfun(t_callb fn);

#ifdef __cplusplus
}
#endif

callb.c:

#include "callb.h"

void cfun(t_callb fn) {
 fn();
}

main.cpp中:

#include <iostream>
#include <string>
#include "callb.h"

void myfn() {
  std::string s( "My Callb Except" );
  throw s;
}

int main() {
  try {
    cfun(myfn); 
  }
  catch(std::string s) {
    std::cout << "Caught: " << s << std::endl;
  }
  return 0;
}

答案 4 :(得分:0)

如果你从sqlite调用的回调来自你调用sqlite3_exec()的同一个线程,那么在callstack中的某个地方应该被更高级别的catch捕获。

自己进行测试应该是直截了当的,不是吗?

[编辑] 在自己挖掘了一点之后,我发现C ++标准对于c语言函数在抛出异常时应该具有的行为有些模糊。

您绝对应该使用API​​期望的错误处理机制。否则,您主要是API本身处于未定义状态,任何进一步的调用都可能失败/崩溃。