Lua userdata指针的生命周期

时间:2016-08-02 10:54:39

标签: c++ lua lua-userdata

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

2 个答案:

答案 0 :(得分:3)

引用(或者由于Lua是用C语言编写的指针)将在userdata的生命周期内保持有效。

Lua的首席架构师在Lua-l mailing list上发表了这篇文章:

  

引用:2006年4月18日; Roberto Ierusalimschy

     

谨慎是关于字符串,而不是关于userdata(尽管我们实际上是这样)   没有在手册中明确说明)。我们无意   允许用户数据地址在GC期间更改。与字符串不同   是Lua中的内部数据,用户数据的唯一目的就是使用它   通过C代码,它希望事物保持原样:)

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

有几个原因可能比lightuserdata更喜欢完整的用户数据:

  • 完整的userdata可能有自己的uservalue和metatable(所有lightuserdata共享相同的metatable)
  • 通过__gc元方法
  • 完成
  • 使用userdata(luaL_newmetatableluaL_setmetatable等)的几个便捷API函数。

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

答案 1 :(得分:2)

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

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

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