如果我创建一个 userdata 对象并将其存储在表中,然后在 C/C++ 中获取对它的引用,该引用的有效期为多长时间?只要用户数据保存在 Lua 中的表中,C/C++ 中的引用是否保证有效?或者是否存在 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
和少量用户数据?
最佳答案
引用(或指针,因为 Lua 是用 C 编写的)将在用户数据的生命周期内保持有效。
Lua 的首席架构师在 Lua-l mailing list 上解决了这个问题:
Quote: Apr 18, 2006; Roberto Ierusalimschy
The caution is about strings, not about userdata (although we actually did not say that explicitly in the manual). We have no intention of allowing userdata addresses to change during GC. Unlike strings, which are an internal data in Lua, the only purpose of userdata is to be used by C code, which prefer that things stay where they are :)
您可以通过将用户数据锚定在以下状态来控制其生命周期:
- 在registry
- 作为 uservalue 与另一个对象的生命周期相关联
- 作为全局存储在 pseudo-index 处的表中
LUA_RIDX_GLOBALS
您可能更喜欢完整用户数据而不是轻量级用户数据的原因有以下几个:
- 完整的用户数据可能有自己的用户值和元表(所有轻型用户数据共享同一个元表)
- 通过
__gc
元方法完成 - 一些用于处理用户数据的便捷 API 函数(luaL_newmetatable、luaL_setmetatable 等)
在 C++ 中从类创建用户数据的常用方法是使用 pointer-to-pointer idiom :
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;
}
关于c++ - Lua 用户数据指针的生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38718475/