将 Lua 包装成 C++ class 的问题

Problems with wrapping Lua into a C++ class

我在 C++ 中使用 Lua C API 并将其包装到 class 中,如下所示:

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;
}

我遇到的问题:

实施:

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 对象的引用,它 一个 LuaScripting 对象.

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

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

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

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

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

如果您希望能够 移动 LuaScripting 对象 - 例如,如果您希望将它们存储在一个向量中,但仍然不复制它们 - 您可以定义 移动构造函数 移动赋值运算符 ,这超出了本答案的范围。


您的 math_sin 测试用例没有 return 堆栈上的任何值,因为...您的脚本没有 return 任何值。尝试 return math_sin(target_value) 而不是 math_sin(target_value).