2013-03-17 3 views
2

У меня есть некоторые объекты lua, которые являются оболочками для объектов C++, они содержат локальную ссылку на объект C++ и называют ее.Как создать оболочку lua C++ из C++

Теперь я хочу, чтобы некоторые функции в C++ возвращали эти оболочки, поэтому мне нужно вызвать эту функцию lua, а затем установить на ней объект C++.

У меня возникли сбои, и я подозреваю, что я не справляюсь со стволом lua. Например, если я запрашиваю lua_top перед тем, как выйти из функции, которая создает объект wrapper + C++, я получаю 5 в качестве результата, не должен ли он быть 1, если я верну 1 объект?

Так вот, что я делаю, может быть, я делаю это неправильно, возможно, есть лучший способ сделать это.

C++, .h:

#define gLuaGet(L, var, type) \ 
    if (lua_istable(L, 1)) {\ 
     lua_getfield(L, 1, "CObj");\ 
     lua_replace(L, 1);\ 
    }\ 
    type& var = *(type*)lua_touserdata(L, 1); 

#define gLuaCreate(L, type) new (lua_newuserdata(L, sizeof(type))) type(); 

class MyObject { 
    public: 
     MyObject(); 

     int somefunc(); 
}; 

int MyObjectCreate(lua_State *L); 
int MyObjectCallSomefunc(lua_State *L); 

C++ .cpp:

int MyObject::somefunc() { 
    std::cerr << "in c++ function" << std::endl; 
    return 123; 
} 

int MyObjectCreate(lua_State *L) { 
    gLuaCreate(L, MyObject); 
    return 1; 
} 

int MyObjectCallSomefunc(lua_State *L) { 
    gLuaGet(L, obj, MyObject); 
    int r = obj.somefunc(); 
    lua_checkstack(L, 1); 
    lua_pushnumber(L, r); 
    return 1; 
} 

Lua обертка:

function MyObject(donotinit) 
    self = {} 
    self.CObj = nil 

    if (donotinit == nil) then 
     self.CObj = MyObjectCreate() 
    end 

    self.setCObject = function(obj) 
     self.CObj = obj 
    end 

    self.somefunc = function() 
     return MyObjectCallSomeFunc(self) 
    end 

    return self 
end 

Теперь я хочу какой-нибудь другой обертку, чтобы вернуть MyObject, который созданный в C++, так что вот код C++, который вызывается из новой обертки (для лучшей читаемости я удалил проверку на чувствительность на lu a_pcall):

int returnLuaMyObject(lua_State *L) { 
    gLuaGet(L, obj, MyOtherObject); 
    MyObject *myObject = obj.getMyObject(); // get c++ part 
    lua_getglobal(L, "MyObject"); // create lua part 
    lua_pushnumber(L, 1); // and tell it not to initialize the self.CObj 
    lua_pcall(L, 1, 1, 0); 
    lua_getfield(L, -1, "setCObject"); // call the setCObject function 
    lua_pushlightuserdata(L, myObject); // give c++ object as param 
    lua_pcall(L, 1, 0, 0); 
    // at this point lua_gettop(L); returns 5, can this be correct? 
    return 1; 
} 

Ну, если я вызвать эту функцию с помощью Lua обертке теперь пару раз, кажется, все хорошо, но если я называю это позволяет сказать, что в 50 раз в цикле в то время, его сбой на случайные моменты времени (но всегда на той же линии C++)

Я делаю что-то не то здесь? Хорошо ли для вершины lua stack быть 5 в этой точке, где она возвращает только один объект?

ответ

2

Это то, что ваш стек Lua будет выглядеть после каждой функции/макровызове, если я читаю это правильно

int returnLuaMyObject(lua_State *L) { 
    // arg 
    gLuaGet(L, obj, MyOtherObject); // arg.CObj 
    MyObject *myObject = obj.getMyObject(); 
    lua_getglobal(L, "MyObject"); // arg.CObj _G.MyObject 
    lua_pushnumber(L, 1); // arg.CObj _G.MyObject 1 
    lua_pcall(L, 1, 1, 0); // arg.CObj obj 
    lua_getfield(L, -1, "setCObject"); // arg.CObj obj obj.setCObject 
    lua_pushlightuserdata(L, myObject); // arg.CObj obj obj.setCObject myObject 
    lua_pcall(L, 1, 0, 0); // arg.CObj obj 

    // at this point lua_gettop(L); returns 2. 
    // If you end this function with return 1, only obj is returned 
    // to Lua, everything else is discarded. 

    return 1; 
} 

(Для чего это стоит, при написании Lua код, который я свято поместить такие комментарии, что на каждой отдельной линии, которая беспорядочна для стека Lua, поэтому я всегда знаю, над чем я работаю. После того, как вы запомните побочные эффекты функции Lua, это затрудняет поиск ошибок)

Это должно быть хорошо, если returnLuaMyObject из Луа. Если вы вызываете его в цикле на C++, ваш стек будет запутан, так как он оставлен с двумя вещами в стеке, а некоторые из ваших функций жестко запрограммированы для работы с индексом 1.

Лучший способ сделать это то, что Cubic предложил и использовал некоторые шаблоны, а не макросы. Вы также должны избегать использования индексов hardcoded, когда это возможно, чтобы вы могли повторно использовать свои функции в ситуациях, когда интересующий вас объект находится в разностном месте в стеке. Например, ваш gLuaGet должен принять индекс в качестве аргумента, чтобы вы могли его использовать в любом месте.(Я бы также избавиться от obj аргумента и отбросить всю последнюю строку макроса, он делает неясным, где переменная obj в настоящее время объявлена.

Я написал библиотеку для себя (по совпадению под названием LuaWrapper, расположенный here), который позволяет вам делать то, что вы хотите, без особых хлопот. Вы можете использовать luaW_to и luaW_push, чтобы нажимать и получать указатели от Lua, точно так же, как они были числами или строками. Я просто бросаю его туда, потому что мне это нравится чем предложение Luabind или toLua ++

0

Верхняя часть стека в Lua равна -1, а не 1 (или lua_gettop(state)). Кроме того, для этого вам действительно нужно использовать шаблоны, а не макросы. Или еще лучше, если у вас нет причины, вы можете использовать luabind или tolua++. В настоящее время я пишу что-то, что работает по существу так же, как и luabind, но использует возможности C++ 11, чтобы отказаться от зависимостей boost, хотя он еще не близок к завершению.

Смежные вопросы