Alex
Alex

Reputation: 245

Lua and C++ Binding - What does this line mean?

The following code is to bind a C++ class to Lua.

void registerPerson(lua_State *lua, Person *person)
{
    //We assume that the person is a valid pointer
    Person **pptr = (Person**)lua_newuserdata(lua, sizeof(Person*));
    *pptr = person; //Store the pointer in userdata. You must take care to ensure 
                    //the pointer is valid entire time Lua has access to it.

    if (luaL_newmetatable(lua, "PersonMetaTable")) //This is important. Since you 
        //may invoke it many times, you should check, whether the table is newly 
        //created or it already exists
    {
        //The table is newly created, so we register its functions
        lua_pushvalue(lua, -1);  
        lua_setfield(lua, -2, "__index");

        luaL_Reg personFunctions[] = {
            "getAge", lua_Person_getAge,
            nullptr, nullptr
        };
        luaL_register(lua, 0, personFunctions);
    }

    lua_setmetatable(lua, -2);
}

The above code is from an answer to this question. It binds a C++ class(Person) to Lua. As you can see it, this function

Creates a new user data and pushes it to the top of the stack. Stores the person pointer in the user data.

Creates a metatable using luaL_newmetatable named "PersonMetaTable" and by now the metatable should be at the top of the stack.

According to the documentation, the lua_pushvalue function copies the element at the given index to the top of the stack. But here, the function is called with the argument -1, which I think copies the metatable (as it is on the top of the stack), am I correct?

Why should the metatable be copied? What is the purpose of this line?

lua_pushvalue(lua, -1); 

Upvotes: 2

Views: 402

Answers (1)

Colonel Thirty Two
Colonel Thirty Two

Reputation: 26549

lua_setfield pops the assigned value off the stack, so you need the lua_pushvalue to duplicate the metatable reference so that it's not lost when setting the __index table.

Begin: [Person*, metatable]
lua_pushvalue: [Person*, metatable, metatable] <- metatable duplicated and pushed onto stack
lua_setfield: [Person*, metatable] <- metatable duplicate is popped. metatable.__index = metatable
lua_setmetatable: [Person*] <- metatable is popped. getmetatable(Person*) = metatable

Upvotes: 2

Related Questions