簡體   English   中英

C++ 異常會通過 C 代碼安全地傳播嗎?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM