繁体   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