Будут ли исключения C ++ безопасно распространяться через код C? - PullRequest
31 голосов
/ 20 января 2010

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

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

Ответы [ 5 ]

29 голосов
/ 20 января 2010

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

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

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

14 голосов
/ 20 января 2010

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

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

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

10 голосов
/ 20 января 2010

SQLite ожидает, что вы вернете SQLITE_ABORT при ошибке и код возврата 0 для отсутствия ошибок. Таким образом, вы должны обернуть все ваши обратные вызовы C ++ в попытку catch . Затем в catch возвращают код ошибки SQLite SQLITE_ABORT, в противном случае ноль.

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

1 голос
/ 20 января 2010

Это был действительно интересный вопрос, и я сам проверил его из любопытства. На моей 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;
}
0 голосов
/ 20 января 2010

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...