如何销毁和重新创建一个lua_State?

为了一个学校项目,我正在使用Lua向游戏引擎添加一些脚本功能。该引擎加载速度很慢,因此,为了避免每次更改Lua脚本时都要重新启动引擎,我希望能够只重载脚本。我希望能够以一种安全可靠的方式进行操作,即使其他脚本作者以无法预测的方式污染了全局状态。

在我看来,最简单的方法是在我的C++代码中简单地销毁lua_State,然后创建一个新的,重新绑定我的函数并重新加载所有必要的脚本。然而,我在正确使用它方面遇到了一些问题。我有一个用作Lua虚拟机接口的类,它具有以下构造函数和析构函数:

LuaInterface::LuaInterface()
{
  luaVM = lua_open();
  luaL_openlibs(luaVM);

  // Create the ortsgfx table.
  lua_newtable(luaVM);
  lua_setglobal(luaVM, TABLE_NAME);
}

LuaInterface::~LuaInterface()
{
  // Close the Lua virtual machine
  lua_close(luaVM);
}

请注意,在对象的析构函数执行时调用了lua_close(luaVM)。我试图使用以下代码从游戏引擎重置Lua:

lua.~LuaInterface();
lua = LuaInterface();
initLua();

(当然,Lua是一个LuaInterface对象。)当我尝试初始化我的一个表格时,这会导致initLua()中的分段错误。但是,如果我在析构函数中删除lua_close(luaVM)的调用,则一切都可以正常工作。

我做错了什么?此外,重新加载我的Lua脚本还有更好的方法吗?

原文链接 https://stackoverflow.com/questions/8282862

点赞
stackoverflow用户726361
stackoverflow用户726361

我没有看到 initLua 的源代码,所以只能猜测,但是...

通常情况下,你不应该像那样随意地玩弄构造函数和析构函数。只需要做以下操作即可:

lua = LuaInterface();
initLua();

这个类应该有一个赋值运算符,以管理它所拥有的 lua_State

2011-11-27 01:00:25
stackoverflow用户12048
stackoverflow用户12048

我有 C ++ 的经验,但没有 Lua 的经验,所以这是我的猜测:

您的 LuaInterface 类可能没有实现赋值运算符和复制构造函数,否则您可能会与默认构造函数和析构函数一起发布它们。请参阅三个原则:

http://en.wikipedia.org/wiki/Rule_of_three_(C++_programming)

如果是这样,那么这行就是导致错误的原因:

lua = LuaInterface();

因为右侧的 LuaInterface() 将构造一个临时实例,并且自动生成的 operator= 将把 lua_State 复制到 lua 中。在此行之后,右侧的无名临时对象将被销毁并释放相同的 lua_State,该 lua_State 也认为自己拥有它。

三种解决方案浮现在脑海中:

  • 通过声明私有复制构造函数和赋值运算符并永远不实现它们,使 LuaInterface 不能复制。 (这是相对常见的:http://www.artima.com/cppsource/bigtwo2.html)然后添加一个 LuaInterface.reset() 成员函数,该函数与析构函数执行相同的操作,然后是构造函数的操作。您可以通过将共享部分移动到私有 init() 函数来使代码保持清洁。 (请注意,在此函数中使用 C++ 异常会将对象留在无效状态。)
  • 使 LuaInterface 不能复制,但是不使用 LuaInterface lua 变量,而是使用指针或 boost::optional<LuaInterface> lua。这样,您可以销毁和重新创建变量,而不必手动调用析构函数。
  • 通过使用新的 std::shared_ptr 使 LuaInterface 成为共享引用类。您只需使用带有 std::shared_ptr<LuaState> luaVM 成员变量而不是原始指针,并在构造函数中调用:

luaVM.reset(lua_open(), lua_close);

在这种情况下,您甚至不需要析构函数,但是您应该详细了解 shared_ptr 以及现在自动生成的成员执行什么操作。

采用这三种解决方案之一后,您可以使用简单的赋值来重新创建状态:

lua = LuaInterface();

现在,我希望问题确实在于 C ++,而不是在于 Lua。 :)

2011-11-27 01:20:36
stackoverflow用户298661
stackoverflow用户298661
lua.~LuaInterface();
lua = LuaInterface();
initLua();

这是未定义行为。你应该简单地使用lua = LuaInterface();。你还有不遵守三大原则的其他问题,但这也是UB。

2011-11-27 20:32:31
stackoverflow用户264712
stackoverflow用户264712

(来自未来的问候!我从另一个 Lua 问题跑到这里,但是我震惊地看到这个问题的回答如此之差。希望我能帮助这个问题的未来访问者。)

如果您要进行就地销毁,那么您需要跟进就地构建。你的方法是错误的。

 lua.~LuaInterface();
 new (&lua) LuaInterface();

从那里,我建议您熟悉 C++11 移动语义。然后,您可以使用漂亮的语法使类起作用。

lua = LuaInterface();
// 拆除旧实例,构建新实例,并移动到您的变量。

虽然我不建议使用放置销毁和放置新方法,但您可以使用这种方式实现赋值运算符。

LuaInterface& LuaInterface::operator=(LuaInterface&& other)
{
    if (this != &other)
    {
        this->~LuaInterface();
        new (this) LuaInterface(other);
    }

    return *this;
}
2014-04-09 15:17:09