Подтвердить что ты не робот

Будут ли исключения С++ безопасно распространяться через C-код?

У меня есть приложение на С++, которое вызывает SQLite (SQLite находится в C) sqlite3_exec(), который, в свою очередь, может вызвать функцию обратного вызова, реализованную на С++. SQLite скомпилирован в статическую библиотеку.

Если исключение ускорит мой обратный вызов, он будет безопасно распространяться через код C SQLite на код С++, вызывающий sqlite3_exec()?

4b9b3361

Ответ 1

Я предполагаю, что это зависит от компилятора. Однако бросать исключение в обратный вызов было бы очень плохой идеей. Либо он будет плоский, либо не работает, либо код C в библиотеке SQLite не сможет его обработать. Рассмотрим, является ли это некоторым кодом в SQLite:

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

Если исключение "работает", код C не имеет возможности поймать его, и p никогда не будет освобожден. То же самое касается любых других ресурсов, которые библиотека, возможно, выделила, конечно.

Ответ 2

Уже существует протокол для обратного вызова, чтобы прервать вызов API. Из документы:

Если возвращается обратный вызов sqlite3_exec() отличная от нуля, процедура sqlite3_exec() возвращает SQLITE_ABORT без вызова обратный вызов снова и без запуска любые последующие операторы SQL.

Я настоятельно рекомендую вам использовать это вместо исключения.

Ответ 3

SQLite ожидает, что вы вернете ошибку SQLITE_ABORT и код возврата 0 без ошибок. Таким образом, вы должны обернуть весь ваш обратный вызов С++ в try catch. Затем в catch вы получите код ошибки SQLite SQLITE_ABORT, в противном случае - ноль.

Проблемы будут возникать, если вы обходите возврат через SQLite, поскольку он не освободит/не завершит какой бы то ни было код после возврата из вашего обратного вызова. Это вызовет неисчислимые проблемы, потенциально некоторые из которых могут быть очень неясными.

Ответ 4

Если ваш callback, вызванный из sqlite, из того же потока, из которого вы вызвали sqlite3_exec(), бросок где-то в стоп-кассе должен быть пойман путем улова более высокого уровня.

Тестирование этого себя должно быть простым, нет?

[править] После копания немного больше я узнал, что стандарт С++ несколько неопределенен в отношении того, какое поведение должна вызывать функция С++, вызванная из c, при метании исключения.

Вы должны обязательно использовать механизм обработки ошибок, ожидаемый API. В противном случае вы будете главным образом самим API в состоянии undefined, и любые дальнейшие вызовы могут потенциально сбой/сбой.

Ответ 5

Это был действительно интересный вопрос, и я испытал это из любопытства. В моей ОС X w/gcc 4.2.1 ответ был ДА. Он работает отлично. Я думаю, что настоящий тест будет использовать gcc для С++ и некоторых других (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;
}