4

如果我创建一个 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轻量级用户数据吗?

4

2 回答 2

4

引用(或因为 Lua 是用 C 编写的指针)将在用户数据的生命周期内保持有效。

Lua 的首席架构师在Lua-l 邮件列表中解决了这个问题:

引用:2006 年 4 月 18 日;罗伯托·耶鲁萨利姆斯奇

需要注意的是字符串,而不是用户数据(尽管我们实际上并没有在手册中明确说明)。我们无意允许用户数据地址在 GC 期间更改。与 Lua 中作为内部数据的字符串不同,userdata 的唯一目的是供 C 代码使用,C 代码更喜欢保持原样:)

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

有几个原因,您可能更喜欢完整的用户数据而不是轻用户数据:

  • 完整的 userdata 可能有自己的 uservalue 和 metatable(所有 lightuserdata 共享同一个 metatable)
  • 通过元__gc方法完成
  • 用于处理用户数据的几个便利 API 函数(luaL_newmetatableluaL_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;
}
于 2016-08-03T21:51:41.990 回答
3

在 Lua 垃圾收集器确定表(或表元素)不再在任何地方使用并且可以安全删除之前,它是有效的。使用元方法,Lua 会在垃圾收集发生时通知您。

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

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

于 2016-08-02T11:56:04.683 回答