簡體   English   中英

從Lua調用函數時如何處理C ++異常?

[英]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;
}

注意:我知道我不必在那里使用字符串變量,但它是為了證明問題。

這是我的兩個問題:

  1. 當我從Lua字符串構造函數調用此函數時可能會拋出異常。 那是問題嗎? Lua會處理它並正確解開Lua堆棧嗎? 我不這么認為。 我怎么解決這個問題? 我是否需要在所有此類代碼周圍添加try/catch並將異常轉換為lua_error? 是不是有更好的解決方案?

  2. 我可能通過將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.

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