luaL_setmetatable() 覆盖其它值的元表。

在我的项目中有不同的元表。但是,如果我创建一个值A并将其赋予元表“X”,并创建第二个值B并附加元表“Y”,则A也会得到Y元表!这里是一个简化的C函数进行演示:

#include <errno.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
//应该创建 t ["obj"] = <userdata>,其中 metatable =“Obj”,但得到了“OtherType”
int create_table_with_object(lua_State *L)
{
        lua_newtable(L);
        lua_pushlightuserdata(L, (void *)0x1234);
        luaL_setmetatable(L, "Obj"); //此类型已使用lua_newmetatable()进行注册
        lua_setfield(L, -2, "obj");

        luaL_newmetatable(L, "OtherType");
        lua_pushinteger(L, 70);
        lua_setfield(L, -2, "ICameFromOtherType");
        lua_pop(L, 1); //只是一个虚拟表

        //如果我们创建另一个userdata对象,第一个对象
        //得到与此对象相同的类型!
        //Obj->更改为“OtherType”
        //### CRITICAL SECTION STRT ###
        lua_pushlightuserdata(L, (void *)0x5555);
        luaL_setmetatable(L, "OtherType");
        lua_setglobal(L, "JustADummyObj"); //这会从堆栈中删除值!
        //### CRITICAL SECTION END ###
        return 1;
}

int main(void)
{
        lua_State *L = luaL_newstate();
        luaL_openlibs(L);

        luaL_loadfile(L, "bug.lua");

        lua_pushcfunction(L, create_table_with_object);
        lua_setglobal(L, "create_table_with_object");

        luaL_newmetatable(L, "Obj");
        lua_pop(L, 1);

        int error;
        if (error = lua_pcall(L, 0, 0, 0))
        {
                fprintf(stderr, "Fatal error: \n");
                fprintf(stderr, "%s\n", lua_tostring(L, -1));
                return 1;
        }
        lua_close(L);

        return 0;
}

Lua代码:

local a = create_table_with_object()
print(getmetatable(a.obj).__name)

输出为“OtherType”,但应为“Obj”。似乎第二次调用lua_setmetatable()覆盖了来自其他值的表?!

点赞
用户478141
用户478141

Ok, 解决了! 在 Lua 中,lightuserdata 共享一个元表(而不是每个值都有一个元表)。因此,更改一个 lightuserdata 值的表会更改所有其他 lightuserdata 值的表!

2015-04-20 14:58:38