2011-11-27 80 views
2

对于一个学校项目,我使用Lua为游戏引擎添加一些脚本功能。引擎加载速度很慢,所以不必每次更改我的一个Lua脚本时重新启动它,我希望能够重新加载脚本。我希望能够以一种安全可靠的方式做到这一点,即使其他剧本作者以不可预知的方式污染了全球国家。如何破坏并重新创建一个lua_State

在我看来,最简单的方法是简单地销毁我的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脚本?

+0

lua_close()是否执行任何内存解除分配? – ScarletAmaranth

回答

6

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

LuaInterface类可能没有实现一个赋值操作符和拷贝构造函数,否则你或许会公布他们的默认构造函数和析构函数沿。看到三的规则:

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

如果是这样,那么这条线是什么原因造成的错误:

lua = LuaInterface(); 

因为LuaInterface()上将建一个临时的实例的权利,以及自动生成operator=会将lua_State复制到lua。在此行之后,右侧的未命名临时文件将被销毁并释放与lua相同的lua_State

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

  • LuaInterface不可复制声明一个私人拷贝构造函数和赋值运算符,从来没有实现它们。(这是比较常见的:http://www.artima.com/cppsource/bigtwo2.html)然后添加一个LuaInterface.reset()成员函数,它的作用与析构函数相同,后面的构造函数会这样做。您可以通过将共享部分移动到专用init()函数来保持代码清洁。 (注意在此函数中使用C++异常,使对象处于无效状态。)
  • 使LuaInterface不可复制,但不是使用变量,而是使用指针或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的一面。 :)

3

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

通常你不应该只是扮演无可奈何地与构造函数和析构函数类的。只要做到

lua = LuaInterface(); 
initLua(); 

类应该有一个赋值运算符采取lua_State的IT拥有的照顾。

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

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

+0

直接调用析构函数后要做的唯一明智的事情是重新初始化变量new或取消分配变量占用的内存,但即使这样也没有意义,因为直接调用析构函数在初始化之后才是合理的新增放置的变量... – Xeo

0

(从未来的问候!我在这里结束了从另一个Lua的问题,但我很震惊地看到问题如此糟糕解决。希望我能帮助未来的游客到这个问题。)

如果你要做一个就地破坏,你需要跟进一个就地建设。你的方法是错误的。

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

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

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

虽然我不建议使用放置析构函数和放置新的,你可以实现你的赋值操作符的方式。

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

    return *this; 
} 
相关问题