Время жизни указателей пользовательских данных 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, который предпочитает, чтобы все оставалось там, где они есть:)

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

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

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

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

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

Другие вопросы по тегам