Как синхронизировать сборку мусора Lua и C++

Я пытаюсь внедрить lua в существующее приложение C++ и сделал для него стандартную процедуру, наследуя от класса, который выполняет эту работу. Серьезная проблема, которую я вижу, заключается в том, что если открытый объект освобождается или удаляется в среде C++, тогда вызов из Lua вызовет сбои. Если память удаляется программой с помощью «удалить», то я могу, возможно, написать оболочку для удаления, чтобы позаботиться об освобождении памяти и в Lua, но если память была выделена C++ и освобождена, когда соответствующая переменная выходит за рамки Я не вижу способа, как это выяснить, а затем предпринять соответствующие действия в пространстве lua, у кого-нибудь есть идеи по этому поводу?

Спасибо.


person Milind    schedule 02.09.2011    source источник
comment
Когда вы указываете значение lua в качестве пользовательских данных, lua позаботится об освобождении памяти для этого объекта. Таким образом, вы не должны вызывать delete по указателю, который вы дали lua в качестве пользовательских данных.   -  person Seth Carnegie    schedule 02.09.2011
comment
Похоже, что деструктор класса — это общий метод очистки, который вы ищете, поскольку он вызывается, когда объект стека выходит за пределы области видимости и когда вы вызываете delete для динамически выделенного объекта.   -  person Christian Rau    schedule 02.09.2011


Ответы (3)


В общем, практически у каждой оболочки Lua есть какой-то способ решить, кому какая память принадлежит. То есть, принадлежит ли объект (и, следовательно, будет удален) Lua или вашему приложению.

Если вы дали Lua указатель на объект, которым владеет C++, то вы должны найти способ гарантировать, что Lua не будет использовать этот указатель после того момента, когда C++ его удалит. Есть несколько способов избежать этого. Один из способов — передать право собственности на Lua.

Другой способ — использовать boost/std::shared_ptr, который позволяет вам разделять владение между C++ и Lua. Если вы делаете это вручную, то вы создаете некоторые нелегкие пользовательские данные размером с shared_ptr в Lua. Вы прикрепляете к нему метаметод очистки, который уничтожит shared_ptr, и используете Placement-new для создания shared_ptr в пользовательских данных Lua. На самом деле Luabind имеет эту встроенную функцию: если вы передаете shared_ptr в Lua, то они оба разделяют владение памятью.

Вы также можете использовать boost/std::weak_ptr. Это объект, который вы запрашиваете, чтобы получить shared_ptr. Идея состоит в том, что вы не должны держать указатель на месте; вы временно запрашиваете его по мере необходимости, но постоянно сохраняете только weak_ptr. Если объект потерял все свои ссылки shared_ptr, то запрос weak_ptr вернет нулевой указатель.

person Nicol Bolas    schedule 02.09.2011

Вам придется использовать оболочку RAII, которая может привязываться к экземпляру Lua с помощью реестра и предоставлять значения Lua с помощью таблицы — вы можете удалить из нее внутренний указатель, когда закончите.

template<typename T> class LuaExposedValue {
    T t;
    lua_State* ls;
public:
    LuaExposedValue(lua_State* L) {
        // set registry[&t] = { &t }
        ls = L;
    }
    ~LuaExposedValue() {
        // remove &t from the table
    }
}

В качестве альтернативы, просто запретите Lua доступ к ней после того, как переменная исчезнет, ​​и пусть скриптер позаботится об этом.

Наконец, вы можете просто выделить все, к чему Lua может получить доступ, используя Lua GC.

person Puppy    schedule 02.09.2011

Отказ от ответственности: я написал библиотеку, которую собираюсь порекомендовать

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

Вы можете использовать luaW_push<MyType>(L, myObj); для отправки ваших объектов в Lua. Lua не будет владеть объектами, которые вы создаете из C++, если вы не запустите для них luaW_hold<MyType>. Другими словами, если вы не сообщите Lua об этом, он не будет собирать мусор для вашего объекта.

И наоборот, вы можете использовать MyType.new() в своем коде Lua для создания объекта, которым Lua действительно владеет. Это будет сборщик мусора, как и следовало ожидать. Если вы хотите передать право собственности C++, вы можете вызвать luaW_release<MyType> для своего объекта.

Существуют также такие функции, как luaW_to<MyType> и luaW_check<MyType>, и в ограниченной степени они правильно поддерживают наследование от базовых типов (хотя на данный момент допускается только одиночное наследование). Я обнаружил, что это значительно упрощает мои собственные попытки совместного использования C++ и Lua, поскольку делает управление владением указателями очень простым.

person Alex    schedule 02.09.2011