如何销毁并重新创建 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 脚本?
For a school project, I'm using Lua to add some scripting functionality to a game engine. The engine is quite slow to load, so rather than having to restart it every time I change one of my Lua scripts, I'd like to be able to just reload the scripts. I'd like to be able to do this in a way which is safe and reliable even if other script authors have polluted the global state in unpredictable ways.
In my mind, the easiest way to go about it is to simply destroy the lua_State
in my C++ code, and then create a new one, re-bind my functions and reload all of the necessary scripts. However, I'm having some trouble getting it work properly. I have a class which serves as an interface to the Lua virtual machine, which has the following constructor and destructor:
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);
}
Note that lua_close(luaVM) is called when the object's destructor executes. I attempt to reset Lua from the game engine with the following code:
lua.~LuaInterface();
lua = LuaInterface();
initLua();
(Lua is a LuaInterface object, of course.) This causes a segmentation fault in initLua()
when I try to initialize one of my tables. However, if I remove the lua_close(luaVM)
call in the destructor, then everything works fine.
What am I doing wrong? Additionally, is there a better way to go about reloading my Lua scripts?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我有使用 C++ 的经验,但没有使用 Lua 的经验,所以我的猜测是:
您的
LuaInterface
类可能不会实现赋值运算符和复制构造函数,否则您可能会将它们与默认构造函数和析构函数一起发布。请参阅三法则:http://en.wikipedia.org/wiki /Rule_of_ Three_(C++_programming)
如果是这样,那么这一行就是导致错误的原因:
因为右侧的
LuaInterface()
将构造一个临时的实例,自动生成的operator=
会将lua_State
复制到lua
中。在此行之后,右侧未命名的临时对象将被销毁,并释放lua
也认为拥有的相同lua_State
。我想到了三种解决方案:
LuaInterface
不可复制。 (这是比较常见的:http://www.artima.com/cppsource/bigtwo2.html) 然后添加一个LuaInterface.reset()
成员函数,其作用与析构函数相同,后面是构造函数。您可以通过将共享部分移至私有init()
函数来保持代码整洁。 (注意在此函数中使用 C++ 异常,使对象处于无效状态。)LuaInterface
不可复制,但不要使用LuaInterface lua
变量,而是使用指针或一个boost::可选的LuaInterface lua。这样,您可以销毁并重新创建变量,而无需手动调用析构函数。使用新的
std::shared_ptr
使LuaInterface
成为共享引用类。您只需使用std::shared_ptr即可luaVM
成员变量而不是原始指针,并在构造函数中调用:luaVM.reset(lua_open(), lua_close);
在这种情况下,您甚至不需要析构函数,但您应该阅读
shared_ptr
以及自动生成的成员现在执行的操作。使用这三种解决方案中的任何一种,您都可以使用简单的赋值来重新创建状态:
现在我希望问题确实出在 C++ 方面,而不是 Lua 方面。 :)
I have experience with C++, but not Lua, so here's my guess:
Your
LuaInterface
class might not implement an assignment operator and copy constructor, otherwise you would probably have posted them along with the default constructor and destructor. See the Rule of Three:http://en.wikipedia.org/wiki/Rule_of_three_(C++_programming)
If that is so, then this line is what causes the error:
Because
LuaInterface()
on the right will construct a temporary instance, and the automatically generatedoperator=
will copy thelua_State
over intolua
. After this line, the unnamed temporary on the right-hand side is destroyed and frees the samelua_State
thatlua
also believes to own.Three solutions come to mind:
LuaInterface
noncopyable by declaring a private copy constructor and assignment operator, and never implementing them. (This is relatively common: http://www.artima.com/cppsource/bigtwo2.html) Then add aLuaInterface.reset()
member function that does the same as the destructor, followed by the constructor would do. You can keep your code clean by moving shared parts to a privateinit()
function. (Beware of using C++ exceptions in this function, leaving the object in an invalid state.)LuaInterface
noncopyable, but instead of having aLuaInterface lua
variable, use a pointer or aboost::optional<LuaInterface> lua
. That way, you can destroy and recreate the variable without manually calling the destructor.Make
LuaInterface
a shared reference class by using the newstd::shared_ptr
. You just use astd::shared_ptr<LuaState> luaVM
member variable instead of a raw pointer, and in the constructor you call:luaVM.reset(lua_open(), lua_close);
You do not even need a destructor in this case, but you should read up on
shared_ptr
and what the automatically generated members do now.With either of these three solutions, you can then use simple assignment to recreate the state:
Now I hope the problem is really on C++'s, and not on Lua's side. :)
我没有看到 initLua 的源代码,所以我只能猜测,但是......
你通常不应该随意使用构造函数和析构函数。 类应该
有一个赋值运算符来处理它拥有的 lua_State 。
I don't see the source for
initLua
so I can only guess, but...You usually shouldn't just play willy-nilly with constructors and destructors like that. Just do
The class should have an assignment operator to take care of the
lua_State
s it owns.这是未定义的行为。您应该简单地执行
lua = LuaInterface();
。你还有其他问题,因为不遵守三法则,但这也是UB。This is Undefined Behaviour. You should do simply
lua = LuaInterface();
. You have other problems with not adhering to the Rule of Three, but this is UB as well.(来自未来的问候!我从另一个 Lua 问题中结束了这里,但我很震惊地看到这个问题如此糟糕地得到解决。希望我可以帮助未来的访问者解决这个问题。)
如果你要进行就地销毁,您需要跟进就地施工。你的做法是错误的。
从那里,我建议您熟悉 C++11 移动语义。然后,您可以使用漂亮的语法使该类工作。
虽然我不建议使用布局析构函数和布局 new,但您可以以这种方式实现赋值运算符。
(Greetings from the future! I ended up here from another Lua question, but I was shocked to see the question so poorly addressed. Hopefully I can help future visitors to this question.)
If you're going to do an in-place destruction, you need to follow up with an in-place construction. Your approach is wrong.
From there, I would recommend you familiarize yourself with C++11 move-semantics. Then, you can make the class work using pretty syntax.
While I would not recommend using placement destructor and placement new, you could implement your assignment operator that way.