Как уничтожить и воссоздать lua_State - PullRequest
2 голосов
/ 27 ноября 2011

В школьном проекте я использую Lua, чтобы добавить некоторые скриптовые функции в игровой движок.Движок загружается довольно медленно, поэтому вместо того, чтобы перезапускать его каждый раз, когда я меняю один из моих сценариев Lua, я бы хотел просто перезагрузить сценарии.Я хотел бы иметь возможность делать это безопасным и надежным способом, даже если другие авторы сценариев загрязняют глобальное состояние непредсказуемым образом.

На мой взгляд, самый простой способ сделать этопросто уничтожить lua_State в моем коде C ++, а затем создать новый, заново связать мои функции и перезагрузить все необходимые сценарии.Тем не менее, у меня возникли некоторые проблемы, чтобы заставить его работать правильно.У меня есть класс, который служит интерфейсом для виртуальной машины 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?

Ответы [ 4 ]

6 голосов
/ 27 ноября 2011

У меня есть опыт работы с C ++, но не с Lua, так что вот мое предположение:

Ваш класс LuaInterface может не реализовывать оператор присваивания и конструктор копирования, иначе вы, вероятно, разместили бы их вместе с конструктором и деструктором по умолчанию. См. Правило трех:

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

Если это так, то эта строка вызывает ошибку:

lua = LuaInterface();

Поскольку LuaInterface() справа создаст временный экземпляр, а автоматически сгенерированный operator= скопирует lua_State в lua. После этой строки неназванный временный объект с правой стороны уничтожается и освобождает тот же lua_State, который lua также считает своим.

На ум приходят три решения:

  • Сделать LuaInterface неоткопируемым, объявив конструктор частной копии и оператор присваивания, и никогда не реализовывать их (Это относительно часто встречается: http://www.artima.com/cppsource/bigtwo2.html) Затем добавьте функцию-член LuaInterface.reset(), которая выполняет те же функции, что и деструктор, после чего это сделает конструктор. Вы можете сохранить свой код в чистоте, перемещая общие части в частные init() функция. (Остерегайтесь использования исключений C ++ в этой функции, оставляя объект в недопустимом состоянии.)
  • Сделать LuaInterface некопируемым, но вместо переменной LuaInterface lua используйте указатель или boost::optional<LuaInterface> lua. Таким образом, вы можете уничтожить и воссоздать переменную без ручного вызова деструктора.
  • Сделать LuaInterface общим справочным классом, используя новый std::shared_ptr. Вы просто используете std::shared_ptr<LuaState> luaVM переменную-член вместо необработанного указателя, и в конструкторе вы вызываете:

    luaVM.reset(lua_open(), lua_close);

    В этом случае вам даже не нужен деструктор, но вы должны прочитать shared_ptr и что теперь делают автоматически сгенерированные члены.

С помощью любого из этих трех решений вы можете использовать простое назначение для воссоздания состояния:

lua = LuaInterface();

Теперь я надеюсь, что проблема действительно в C ++, а не в стороне Lua. :)

3 голосов
/ 28 ноября 2011
lua.~LuaInterface(); 
lua = LuaInterface(); 
initLua();

Это неопределенное поведение. Вы должны сделать просто lua = LuaInterface();. У вас другие проблемы с несоблюдением правила три, но это также UB.

3 голосов
/ 27 ноября 2011

Я не вижу источника для initLua, поэтому я могу только догадываться, но ...

Обычно вы не должны просто играть волей-неволей с такими конструкторами и деструкторами.Просто сделайте

lua = LuaInterface();
initLua();

У класса должен быть оператор присваивания, чтобы заботиться о lua_State s, которыми он владеет.

1 голос
/ 09 апреля 2014

(Привет из будущего! Я попал сюда из-за другого вопроса 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...