将Lua封装到C++类中的问题



我在C++中使用Lua C API,并将其包装成一个类,如下所示:

class LuaScripting {
public:
lua_State *lua;
LuaScripting();
~LuaScripting();
bool execute_script(const std::string &script);
};
LuaScripting::LuaScripting() {
lua = luaL_newstate(); /* Opens Lua */
luaL_openlibs(lua); /* Opens the standard libraries */
/* Register our custom function(s) */
lua_register(lua, "write8", lua_write8);
lua_register(lua, "write16", lua_write16);
lua_register(lua, "write32", lua_write32);
lua_register(lua, "read8", lua_read8);
lua_register(lua, "read16", lua_read16);
lua_register(lua, "read32", lua_read32);
lua_register(lua, "math_sin", math_sin);
}
LuaScripting::~LuaScripting() {
lua_close(lua); /* Clean up lua */
}

我测试如下:

int main() {
// Disable buffering
setbuf(stdout, nullptr);
LuaScripting lua_scripting;
testWritingInt8(lua_scripting);
testWritingInt16(lua_scripting);
testWritingInt32(lua_scripting);
testReadingInt32(lua_scripting);
test_math_sin(lua_scripting);
return EXIT_SUCCESS;
}

我遇到的问题:

  • 在第一个testWritingInt8()之后调用类析构函数,它将运行lua_close(lua),即使类实例还没有超出范围。我没有使用任何线程。为什么会发生这种情况
  • 调用lua_close(lua)时程序崩溃,原因是什么
  • 在注释掉lua_close(lua)之后,写测试用例成功运行,但是readXX()math_sin()返回空堆栈,尽管将值推送到堆栈上。为什么

实现:

static int math_sin(lua_State *lua) {
const auto value = luaL_checknumber(lua, 1);
const auto sine_result = sin(value);
lua_pushnumber(lua, sine_result);
return 1;
}

测试用例:

void test_math_sin(LuaScripting &lua_scripting) {
std::stringstream lua_script_builder;
const auto target_value = 90.f;
lua_script_builder << "math_sin(" << target_value << ")";
const auto script_result = lua_scripting.execute_script(lua_script_builder.str());
assert(script_result == LUA_OK);
// TODO Not working
const auto read_value = (int32_t) lua_tonumber(*lua_scripting.lua, -1);
assert(target_value == read_value);
}

我总是使用相同的lua_State *,并且我只调用luaL_newstate()一次。

作为一个尝试修复,我试图将lua状态声明为非指针:

lua_State lua; // error: aggregate ‘lua_State lua’ has incomplete type and cannot be defined

但这样做不会编译。

通过lua_State **lua添加另一个间接级别可以修复lua_close()的崩溃问题,但不会修复任何其他问题。

这是因为您正在复制LuaScripting对象。我打赌testWritingInt8是这样声明的:

void testWritingInt8(LuaScripting lua)

请注意,lua参数不是指向LuaScripting对象的指针或引用,它LuaScription对象。

因此,当您调用testWritingInt8(lua)时,计算机会将LuaScripting对象复制到一个新对象中,调用该函数,并在调用结束时销毁该新对象。

现在,为什么会崩溃?好吧,LuaScripting类没有复制构造函数(LuaScripting(const LuaScripting &)(,所以编译器创建了一个默认构造函数,它只复制所有成员变量——在这种情况下,lua指针被复制。然后,当新对象被破坏时,它释放Lua状态。

解决方案:通过删除复制构造函数,使LuaScripting对象不会被意外复制。还有赋值运算符。

// inside LuaScripting
LuaScripting(const LuaScripting &) = delete;
LuaScripting &operator =(const LuaScripting &) = delete;

然后确保通过引用传递LuaScripting值。

如果你想移动LuaScripting对象,比如说,如果你想将它们存储在向量中,但仍然不复制它们,你可以定义move构造函数move赋值运算符,这超出了这个答案的范围。


您的math_sin测试用例不会在堆栈上返回任何值,因为。。。您的脚本不返回任何值。尝试使用return math_sin(target_value),而不是仅使用math_sin(target_value)

最新更新