如何破坏和重建lua_State
How destroy and recreate a 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脚本?
我有C++的经验,但没有Lua,所以我的猜测是:
LuaInterface
类可能没有实现赋值运算符和复制构造函数,否则可能会将它们与默认构造函数和析构函数一起发布。参见三条规则:
http://en.wikipedia.org/wiki/Rule_of_three_(C++编程(
如果是这样的话,那么这一行就是导致错误的原因:
lua = LuaInterface();
因为右边的LuaInterface()
将构造一个临时实例,而自动生成的operator=
将把lua_State
复制到lua
中。在这一行之后,右侧的未命名临时对象被销毁,并释放lua
也认为拥有的相同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方面。:(
我看不到initLua
的来源,所以我只能猜测,但是。。。
你通常不应该随意使用构造函数和析构函数。只做
lua = LuaInterface();
initLua();
类应该有一个赋值运算符来处理它所拥有的lua_State
。
lua.~LuaInterface();
lua = LuaInterface();
initLua();
这是未定义的行为。你应该简单地做lua = LuaInterface();
。你有其他不遵守三条规则的问题,但这也是UB。
(来自未来的问候!我是从另一个Lua问题来到这里的,但看到这个问题处理得如此糟糕,我感到震惊。希望我能帮助未来的访问者解决这个问题。(
如果你要进行现场破坏,你需要进行现场施工。你的做法是错误的。
lua.~LuaInterface();
new (&lua) LuaInterface();
在此基础上,我建议您熟悉C++11移动语义。然后,您可以使用漂亮的语法使类工作。
lua = LuaInterface();
// Destructs old instance. Constructs new one. Moves into your variable.
虽然我不建议使用placement析构函数和placement new,但可以以这种方式实现赋值运算符。
LuaInterface& LuaInterface::operator=(LuaInterface&& other)
{
if (this != &other)
{
this->~LuaInterface();
new (this) LuaInterface(other);
}
return *this;
}
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- C++Lua用户数据扰乱了Mathfu浮点值
- 使用 LuaBridge 或 Lua 将对象传递给 Lua 函数C++
- 将 Lua 函数块转换为 C 字符串
- 我可以从 lua 5.0.2 加载用 c++ 编写的 lua 5.3.5 dll 吗?
- 使用 lua 协程 API 和lua_close时出现分段错误
- 使用 C++ 自动 Lua 绑定
- 调用 lua 函数的地址为 C/C++?
- lua 5.0.2 模块和 5.3.5 有什么区别?
- 如何将 Lua 添加到C++项目
- 使用 Lua 中的C++库对象
- 如何在C++中将用户数据从一个 Lua 块传递到另一个块
- 如何使用重新定义的打印函数打印Lua表?
- Lua table in C++ dll
- 在运行时环境中使用 C++ w/ Lua
- 将shared_ptr传递给Lua
- luaL_len is missing in Lua 5.1
- 将向量传递给<struct> Lua 表
- 将 Lua 与 C++ DLL 结合使用
- Lua C API - 从C++分配和使用类的对象成员