Lua 用户数据指针的生命周期

Lifetime of Lua userdata pointers

如果我创建一个用户数据对象并将其存储在 table 中,然后在 C/C++ 中获取对它的引用,该引用的有效期为多长时间?只要用户数据保存在 Lua 中的 table 中,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垃圾收集器确定table(或table元素)不再在任何地方使用并且可以安全删除之前,它一直有效。使用元方法,Lua 将在发生垃圾回收时通知您。

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

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

引用(或指针,因为 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 :)

您可以通过将用户数据锚定在以下状态来控制其生命周期:

您可能更喜欢完整用户数据而不是轻量级用户数据的原因有很多:

  • 完整用户数据可能有自己的用户值和元数据table(所有轻量用户数据共享相同的元数据table)
  • 通过 __gc 元方法
  • 完成
  • 用于处理用户数据(luaL_newmetatable, luaL_setmetatable 等)的几个便利 API 函数

在 C++ 中从 class 创建用户数据的常用方法是使用 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;
}