Время жизни указателей пользовательских данных Lua

Если я создаю объект 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 здесь?

3

Решение

Ссылка (или указатель, так как Lua написан на C) будет оставаться действительной в течение всего времени существования пользовательских данных.

Главный архитектор Луа обратился к этому на Lua-l список рассылки:

Цитата: 18 апреля 2006 г .; Роберто Иерусалимский

Осторожность касается строк, а не пользовательских данных (хотя мы на самом деле
не сказал, что явно в руководстве). У нас нет намерения
разрешить изменение адресов пользовательских данных во время GC. В отличие от строк, которые
являются внутренними данными в Lua, единственная цель userdata должна использоваться
кодом C, который предпочитает, чтобы вещи оставались там, где они есть 🙂

Вы можете контролировать время жизни пользовательских данных, привязывая их к состоянию:

Есть несколько причин, по которым вы можете предпочесть полные пользовательские данные легким пользовательским данным:

  • Полные пользовательские данные могут иметь свое собственное значение пользователя и быть доступными для метаданных (все разделы 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;
}
2

Другие решения

Он действителен до тех пор, пока сборщик мусора Lua не определит, что таблица (или элемент таблицы) больше нигде не используется и может быть безопасно удалена. Используя метаметод, Lua уведомит вас, когда произойдет сборка мусора.

http://pgl.yoyo.org/luai/i/lua_newuserdata

https://www.lua.org/pil/29.html

2

По вопросам рекламы [email protected]