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