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?
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:
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.)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. :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With