[英]How to handle C++ exceptions when calling functions from Lua?
我有一個工作的C ++函數,我可以從Lua調用。 為了證明我的問題,這里有一個例子:
int PushHello(lua_State *L){
string str("Hello");
lua_pushlstring(L, str.data(), str.length());
return 1;
}
注意:我知道我不必在那里使用字符串變量,但它是為了證明問題。
這是我的兩個問題:
當我從Lua字符串構造函數調用此函數時可能會拋出異常。 那是問題嗎? Lua會處理它並正確解開Lua堆棧嗎? 我不這么認為。 我怎么解決這個問題? 我是否需要在所有此類代碼周圍添加try/catch
並將異常轉換為lua_error? 是不是有更好的解決方案?
我可能通過將Lua編譯為C ++來解決的另一個問題是,當lua_pushlstring()
調用lua_error()
如果使用longjmp,則不會調用字符串析構函數。 通過編譯為C ++並拋出異常而不是使用longjmp來解決問題嗎?
為了澄清,我可以看到問題1的可能解決方案是:
int PushHello(lua_State *L){
string str;
try{
str.assign("Hello");
catch(exception &e){
luaL_error(L, e.what());
}
lua_pushlstring(L, str.data(), str.length());
return 1;
}
但是這非常難看並且容易出錯,因為需要將try/catch
添加到許多地方。 它可以作為一個宏來完成並放置每個可以拋出的命令,但這不會更好。
我找到了合理的解決方案。 問題是它是否正確。 而不是導出(或通過lua_cpcall調用)原始函數int PushHello(lua_State *L)
一個包裝器int SafeFunction<PushHello>(lua_State *L)
被導出/調用。 包裝器看起來像:
template<lua_CFunction func>
int SafeFunction(lua_State *L){
int result = 0;
try{
result = func(L);
}
// transform exception with description into lua_error
catch(exception &e){
luaL_error(L, e.what());
}
// rethrow lua error - C++ Lua throws lua_longjmp*
catch(lua_longjmp*){
throw;
}
// any other exception as lua_error with no description
catch(...){
luaL_error(L, "Unknown error");
}
return result;
}
你怎么看待這件事? 你看到有什么問題嗎?
Juraj Blaho的回答很棒。 但它有一個缺點:對於使用int SafeFunction<PushHello>(lua_State *L)
導出的每個函數,編譯器將從模板生成所有代碼的副本,就像它是一個宏一樣。 當導出許多小功能時,這將浪費占地面積。
您可以通過定義執行所有作業的公共static
函數來輕松避免此問題,並且template
函數只調用該常用函數:
static int SafeFunctionCommon(lua_State *L, lua_CFunction func){
int result = 0;
try{
result = func(L);
}
// transform exception with description into lua_error
catch(exception &e){
luaL_error(L, e.what());
}
// rethrow lua error - C++ Lua throws lua_longjmp*
catch(lua_longjmp*){
throw;
}
// any other exception as lua_error with no description
catch(...){
luaL_error(L, "Unknown error");
}
return result;
}
template<lua_CFunction func>
int SafeFunction(lua_State *L){
return SafeFunctionCommon(L, func);
}
我不會使用lua_error來表示在lua功能之外發生的錯誤。 如果要添加可在lua范圍內調用的其他lua函數,則將使用lua_error。 如果在執行該函數時發生錯誤,則lua_error將是合適的。
這也是使用Lua時C ++中的堆棧展開的復制品
編輯
如果您擔心被調用的字符串析構函數,為什么不這樣做:
try
{
string str("Hello");
lua_pushlstring(L, str.data(), str.length());
}
catch (exception& e)
{
luaL_error(L, e.what());
}
我意識到這是對你建議的一個微妙的改變但是有區別。 如果拋出異常,則try{}
任何內容都會被破壞。 只需確保您想要破壞的任何內容都在該嘗試中。
Lua不會捕獲C ++異常。 如果你沒有捕獲它,它將被傳遞到調用堆棧,直到它被其他代碼塊捕獲或導致程序崩潰(未處理的異常)。 如果您向Lua調用的函數調用可以拋出異常的函數,則應該在該函數中處理它們。
如果您將Lua編譯為C ++,那么他們將使用C ++異常作為錯誤,而如果您編譯為C則他們將使用longjmp / setjmp。 這基本上意味着拋出這樣的例外沒有什么大不了的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.