2011-11-27 28 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; 
} 
相關問題