如何销毁和重新创建一个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
我有 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。 :)
lua.~LuaInterface();
lua = LuaInterface();
initLua();
这是未定义行为。你应该简单地使用lua = LuaInterface();
。你还有不遵守三大原则的其他问题,但这也是UB。
(来自未来的问候!我从另一个 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;
}
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
我没有看到
initLua
的源代码,所以只能猜测,但是...通常情况下,你不应该像那样随意地玩弄构造函数和析构函数。只需要做以下操作即可:
这个类应该有一个赋值运算符,以管理它所拥有的
lua_State
。