Если я создаю объект userdata и сохраняю его в таблице, то получаю ссылку на него в C / C ++, как долго эта ссылка действительна? Гарантируется ли ссылка в C / C ++ действительной до тех пор, пока пользовательские данные хранятся в таблице в Lua? Или есть риск того, что среда выполнения Lua переместит объект пользовательских данных, лишив его возможности ссылаться на C / C ++?
Вот что я делаю:
// Initially, the stack contains a table
class Foo { ... };
lua_pushstring(L, "my_userdata");
void* mem = lua_newuserdata(L, sizeof(Foo));
new (mem) Foo();
lua_settable(L, -3);
// Later:
lua_pushstring(L, "my_userdata");
lua_gettable(L, -2);
Foo *foo = (Foo*)lua_touserdata(L, -1);
lua_pop(L, 1);
// How long will this pointer be valid?
Мне лучше использовать operator new
а легкая userdata здесь?
Ссылка (или указатель, так как Lua написан на C) будет оставаться действительной в течение всего времени существования пользовательских данных.
Главный архитектор Луа обратился к этому на Lua-l список рассылки:
Цитата: 18 апреля 2006 г .; Роберто Иерусалимский
Осторожность касается строк, а не пользовательских данных (хотя мы на самом деле
не сказал, что явно в руководстве). У нас нет намерения
разрешить изменение адресов пользовательских данных во время GC. В отличие от строк, которые
являются внутренними данными в Lua, единственная цель userdata должна использоваться
кодом C, который предпочитает, чтобы вещи оставались там, где они есть 🙂
Вы можете контролировать время жизни пользовательских данных, привязывая их к состоянию:
LUA_RIDX_GLOBALS
Есть несколько причин, по которым вы можете предпочесть полные пользовательские данные легким пользовательским данным:
__gc
МетаметодРаспространенным способом создания пользовательских данных из класса в C ++ является использование идиома указатель-указатель:
class Foo { ... };
static int new_Foo(lua_State *L) {
// begin userdata lifetime
Foo **ud = static_cast<Foo **>(lua_newuserdata(L, sizeof *ud));
luaL_setmetatable(L, "Foo");
// begin C++ object lifetime
*ud = new Foo();
return 1;
}
// __gc metamethod
static int delete_Foo(lua_State *L) {
Foo **ud = static_cast<Foo **>(luaL_checkudata(L, 1, "Foo"));
// end C++ object lifetime
delete *ud;
// end userdata lifetime
return 0;
}
Он действителен до тех пор, пока сборщик мусора Lua не определит, что таблица (или элемент таблицы) больше нигде не используется и может быть безопасно удалена. Используя метаметод, Lua уведомит вас, когда произойдет сборка мусора.