Как вернуть объект C ++ в lua 5.2?

Как вернуть объект C ++ в lua?

Мой код на C ++ выглядит следующим образом:

class MyClass
{
public:
void say()
{
print("Hello\r\n");
}
};

int test(lua_State* l)
{
MyClass* obj = new MyClass();
lua_pushlightuserdata(l, obj);
return 1;
}

Lua Test выглядит следующим образом:

local a = MyClass:new()
a:say()  <--- OK, beacause I set metatable!!
local b = test()
b:say()  <--- ERROR: attempt to index local 'b' (a userdata value)

Как изменить функцию test (), чтобы она работала нормально?
obj будет авто деструктором от lua?

PS: я поставил MyClass метатабельно следующим

void l_registerClass()
{
lua_newtable(l);
int methods = lua_gettop(l);
luaL_newmetatable(l, "MyClass");
int metatable = lua_gettop(l);
lua_pushvalue(l, methods);
lua_setglobal(l, "MyClass");

lua_pushvalue(l, methods);
l_set(l, metatable, "__metatable");

//set metatable __index
lua_pushvalue(l, methods);
l_set(l, metatable, "__index");

//set metatable __gc
lua_pushcfunction(l, l_destructor);
l_set(l, metatable, "__gc");

//set method table
lua_newtable(l);                // mt for method table
lua_pushcfunction(l, l_constructor);
lua_pushvalue(l, -1);           // dup new_T function
l_set(l, methods, "new");         // add new_T to method table
l_set(l, -3, "__call");           // mt.__call = new_T
lua_setmetatable(l, methods);

// set methods metatable
lua_pushstring(l, "say");
lua_pushcclosure(l, l_proxy, 1);
lua_settable(l, methods);

lua_pop(l, 2);
}

int l_proxy(lua_State* l)
{
int i = (int)lua_tonumber(l, lua_upvalueindex(1));
lua_remove(l, 1);  // remove self so member function args start at index 1
//call real function
MyClass* obj = getInstance();
obj->say();
return 1;
}

Я не должен потерять шаг?
Я не использую Lua Binding Framework, я использую чистую библиотеку Lua.

==== Обновление 1 ====

Спасибо за ответ пользователя 1520427, но ….

int test(lua_State* l)
{
MyClass** c = (MyClass**)lua_newuserdata(l, sizeof(MyClass*));
*c = new MyClass();       // we manage this
lua_getglobal(l, "MyClass");
lua_setmetatable(l, -2);
return 1;
}

и я проверяю это в Lua

local b = test()
print( type(b) )
local meta = getmetatable(b)
for k,v in pairs(meta) do
print("    ", k, v)
end

Луа шоу метатабил это правильно.

userdata
say     function: 00602860
new     function: 00493665

Но Луа все еще показывает ту же ошибку в

b:say()   <-- attempt to index local 'b' (a userdata value)

=== Обновление 2 ===

int test(lua_State* l)
{
MyClass** c = (MyClass**)lua_newuserdata(l, sizeof(MyClass*));
*c = new MyClass();       // we manage this
luaL_getmetatable(l, "MyClass");  //
lua_getglobal(l, "MyClass");
lua_setmetatable(l, -2);
return 1;
}

результат теста lua:

b:say()   <-- attempt to call method 'say' (a nil value)

=== Обновление 3 ===

int test(lua_State* l)
{
MyClass** c = (MyClass**)lua_newuserdata(l, sizeof(MyClass*));
*c = new MyClass();       // we manage this
luaL_getmetatable(l, "MyClass");
luaL_setmetatable(l, "MyClass");  //modify
return 1;
}

Результат теста Lua:

b:say()   <-- calling 'say' on bad self

4

Решение

Вы не связываете то, что вы возвращаете test с классом вы зарегистрировались. Попробуйте что-то вроде:

int test(lua_state* l) {
MyClass** c = lua_newuserdata(l, sizeof(MyClass*)); // lua will manage the MyClass** ptr
*c = new MyClass(); // we manage this
luaL_getmetatable(l, "MyClass");
lua_setmetatable(l, -2);
return 1;
}

Это из головы, но вы поняли идею. Вы уже установили деструктор, поэтому, когда Lua мусор собирает пользовательские данные, он вызовет ваш __gc Функцию, которая должна затем привести, разыменовать и удалить данные.

2

Другие решения

спасибо за user1520427 и lhf
правильный код должен быть следующим:

int test(lua_State* l)
{
MyClass** c = (MyClass**)lua_newuserdata(l, sizeof(MyClass*));
*c = new MyClass();       // we manage this
luaL_setmetatable(l, "MyClass");  //assign MyClass metatable
return 1;
}

Тестовый код Lua работает нормально.

0

По вопросам рекламы [email protected]