如何销毁并重新创建 lua_State

发布于 2024-12-18 03:00:19 字数 905 浏览 2 评论 0原文

对于一个学校项目,我使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

你怎么这么可爱啊 2024-12-25 03:00:19

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

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

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

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

lua = LuaInterface();

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

我想到了三种解决方案:

使用这三种解决方案中的任何一种,您都可以使用简单的赋值来重新创建状态:

lua = LuaInterface();

现在我希望问题确实出在 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:

lua = LuaInterface();

Because LuaInterface() on the right will construct a temporary instance, and the automatically generated operator= will copy the lua_State over into lua. After this line, the unnamed temporary on the right-hand side is destroyed and frees the same lua_State that lua also believes to own.

Three solutions come to mind:

  • Make 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 a LuaInterface.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 private init() function. (Beware of using C++ exceptions in this function, leaving the object in an invalid state.)
  • Make LuaInterface noncopyable, but instead of having a LuaInterface lua variable, use a pointer or a boost::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 new std::shared_ptr. You just use a std::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:

lua = LuaInterface();

Now I hope the problem is really on C++'s, and not on Lua's side. :)

迷迭香的记忆 2024-12-25 03:00:19

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

你通常不应该随意使用构造函数和析构函数。 类应该

lua = LuaInterface();
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

lua = LuaInterface();
initLua();

The class should have an assignment operator to take care of the lua_States it owns.

紫﹏色ふ单纯 2024-12-25 03:00:19
lua.~LuaInterface(); 
lua = LuaInterface(); 
initLua();

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

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

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.

赠意 2024-12-25 03:00:19

(来自未来的问候!我从另一个 Lua 问题中结束了这里,但我很震惊地看到这个问题如此糟糕地得到解决。希望我可以帮助未来的访问者解决这个问题。)

如果你要进行就地销毁,您需要跟进就地施工。你的做法是错误的。

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

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

lua = LuaInterface();
// Destructs old instance. Constructs new one. Moves into your variable.

虽然我不建议使用布局析构函数和布局 new,但您可以以这种方式实现赋值运算符。

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

    return *this;
}

(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.

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

From there, I would recommend you familiarize yourself with C++11 move-semantics. Then, you can make the class work using pretty syntax.

lua = LuaInterface();
// Destructs old instance. Constructs new one. Moves into your variable.

While I would not recommend using placement destructor and placement new, you could implement your assignment operator that way.

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

    return *this;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文