[英]Will C++ exceptions safely propagate through C code?
我有一個 C++ 應用程序,它調用SQLite的(SQLite 在 C 中) sqlite3_exec()反過來可以調用我在 C++ 中實現的回調函數。 SQLite 被編譯成一個靜態庫。
如果異常逃脫了我的回調,它會通過 SQLite 的 C 代碼安全地傳播到調用 sqlite3_exec() 的 C++ 代碼嗎?
我的猜測是這取決於編譯器。 但是,在回調中拋出異常將是一個非常糟糕的主意。 要么它完全不起作用,要么 SQLite 庫中的 C 代碼將無法處理它。 考慮這是否是 SQLite 中的一些代碼:
{
char * p = malloc( 1000 );
...
call_the_callback(); // might throw an exception
...
free( p );
}
如果異常“有效”,則 C 代碼無法捕獲它,並且 p 將永遠不會被釋放。 當然,圖書館可能分配的任何其他資源也是如此。
已經有一個回調協議來中止 API 調用。 從文檔:
如果 sqlite3_exec() 回調返回非零值,sqlite3_exec() 例程將返回 SQLITE_ABORT 而不再次調用回調,也不會運行任何后續 SQL 語句。
我強烈建議您使用它而不是例外。
SQLite 期望您在出錯時返回 SQLITE_ABORT,在沒有錯誤時返回 0 返回碼。 因此,您應該將所有 C++ 回調包裝在 try catch 中。 然后在 catch 中返回 SQLite SQLITE_ABORT 錯誤代碼,否則返回零。
如果您繞過通過 SQLite 返回,則會出現問題,因為在您從回調返回后,它不會釋放/完成它所做的任何代碼。 這可能會導致數不清的問題,其中一些可能非常模糊。
這是一個非常有趣的問題,出於好奇,我自己進行了測試。 在我的帶有 gcc 4.2.1 的 OS X 上,答案是肯定的。 它完美地工作。 我認為真正的測試是將 gcc 用於 C++ 和其他一些(MSVC?,LLVM?)用於 C 部分,看看它是否仍然有效。
我的代碼:
呼叫b.h:
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*t_callb)();
void cfun(t_callb fn);
#ifdef __cplusplus
}
#endif
調用b.c:
#include "callb.h"
void cfun(t_callb fn) {
fn();
}
主.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;
}
如果從 sqlite 調用的回調來自調用 sqlite3_exec() 的同一線程,則調用堆棧中某處的拋出應該被更高級別的捕獲捕獲。
自己測試應該很簡單,不是嗎?
[編輯] 在我自己深入挖掘之后,我發現 C++ 標准對於從 c 調用的 c++ 函數在拋出異常時應該具有的行為有些模糊。
您絕對應該使用 API 期望的錯誤處理機制。 否則,您將主要是 API 本身處於未定義狀態,任何進一步的調用都可能會失敗/崩潰。
沒有一個答案提到使用 -fexceptions 構建您的 C 庫? 輸入 -fno-omit-framepointer 就可以了。 這甚至適用於共享庫(用 C 編寫),只要您從主程序中拋出並再次捕獲主程序。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.