Время жизни указателей пользовательских данных Lua
Если я создаю объект userdata и сохраняю его в таблице, то получаю ссылку на него в C/C++, как долго эта ссылка действительна? Гарантируется ли ссылка в C / C++ действительной до тех пор, пока пользовательские данные хранятся в таблице в Lua? Или есть риск того, что среда выполнения Lua переместит объект userdata, лишив ссылки на него 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 здесь?
2 ответа
Ссылка (или указатель, так как Lua написан на C) будет оставаться действительной в течение всего времени существования пользовательских данных.
Главный архитектор Lua обратился к этому в списке рассылки Lua-l:
Цитата: 18 апреля 2006 г.; Роберто Иерусалимский
Предостережение касается строк, а не пользовательских данных (хотя мы на самом деле не говорили об этом прямо в руководстве). Мы не собираемся разрешать изменение адресов пользовательских данных во время GC. В отличие от строк, которые являются внутренними данными в Lua, единственной целью пользовательских данных является использование кода на C, который предпочитает, чтобы все оставалось там, где они есть:)
Вы можете контролировать время жизни пользовательских данных, привязывая их к состоянию:
- В реестре
- Связано с временем жизни другого объекта как пользовательское значение
- Как глобальный хранится в таблице в псевдоиндексе
LUA_RIDX_GLOBALS
Есть несколько причин, по которым вы можете предпочесть полные пользовательские данные легким пользовательским данным:
- Полные пользовательские данные могут иметь свое собственное значение пользователя и быть доступными для метаданных (все разделы lightuserdata имеют одинаковую метатабильную информацию)
- Завершение через
__gc
Метаметод - Несколько удобных функций API для работы с пользовательскими данными ( luaL_newmetatable, luaL_setmetatable и т. Д.)
Распространенным способом создания пользовательских данных из класса в 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 уведомит вас, когда произойдет сборка мусора.