¿Las excepciones de C ++ se propagarán de forma segura a través del código C?

Tengo una aplicación C ++ que llama a SQLite (SQLite está en C) sqlite3_exec () que a su vez puede llamar a mi función de callback implementada en C ++. SQLite se comstack en una biblioteca estática.

Si una excepción escapa a mi callback, ¿se propagará de manera segura a través del código C de SQLite al código de C ++ que llama a sqlite3_exec ()?

Mi suposición es que esto depende del comstackdor. Sin embargo, lanzar una excepción en la callback sería una muy mala idea. O no funcionará, o el código C en la biblioteca SQLite no podrá manejarlo. Considere si esto es algún código en SQLite:

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

Si la excepción “funciona”, el código C no tiene forma posible de capturarlo, y p nunca se liberará. Lo mismo ocurre con cualquier otro recurso que la biblioteca haya asignado, por supuesto.

Ya existe un protocolo para que la callback aborte la llamada API. De los documentos :

Si una callback sqlite3_exec () devuelve un valor distinto de cero, la rutina sqlite3_exec () devuelve SQLITE_ABORT sin invocar nuevamente la callback y sin ejecutar ninguna instrucción SQL posterior.

Recomiendo encarecidamente que use esto en lugar de una excepción.

SQLite espera que regrese un SQLITE_ABORT en caso de error y un 0 código de retorno para que no haya ningún error. Así que deberías envolver toda tu devolución de C ++ en una captura de prueba . Luego, en la captura devuelve un código SQLite_ABORT de error SQL, de lo contrario, un cero.

Se producirán problemas si omite el retorno a través de SQLite, ya que no liberará ni completará el código que haga una vez que regrese de su callback. Esto causará problemas incalculables potencialmente algunos de los cuales pueden ser muy oscuros.

Esa fue una pregunta realmente interesante y la probé yo mismo por curiosidad. En mi OS X w / gcc 4.2.1, la respuesta fue SÍ. Funciona perfectamente Creo que una prueba real sería usar gcc para el C ++ y algún otro (MSVC ?, LLVM?) Para la parte C y ver si todavía funciona.

Mi código:

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  #include  #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; } 

Si su callback llamada desde sqlite es del mismo hilo desde el que llamó a sqlite3_exec () un lanzamiento en algún lugar de la stack de llamadas debería ser atrapado por una captura de nivel superior.

Probarlo usted mismo debe ser sencillo, ¿no?

[edit] Después de excavar un poco más, descubrí que el estándar de C ++ es algo impreciso sobre el comportamiento que debe tener una función c ++ desde c al lanzar una excepción.

Definitivamente debe usar el mecanismo de manejo de errores que espera la API. De lo contrario, la API en su mayoría se encontrará en un estado indefinido y cualquier otra llamada podría fallar o bloquearse.