使用default_converter和表的luabind问题

时间:2010-02-07 02:01:17

标签: c++ lua luabind

===编辑===

问题实际上比这简单得多,任何包含表的包装函数都会导致问题。如果我包装一个带有luabind :: object的函数,并用一个表参数调用该函数,那么gc会导致一个无效的free()。我开始认为这可能是某种疯狂的编译/链接问题,因为我编译的luabind dylib中有lua符号(导致这些符号的两个副本,一个在该库中,一个在我的二进制中)。也许我有一些lua静态变量或其他东西的重复?我可能只是抓住稻草。

===编辑===

在mac os x 10.6上使用luabind 0.9和gcc 4.2.1

我看到使用lua表中的default_converter会有什么问题(可能?)。

我正在尝试在我的代码中为各种类似列表的类型定义转换器,特别是std :: vector。当我使用这样的default_converter将表传递给c ++方法时,只要调用垃圾收集器,lua就会在无效指针上崩溃。

我可能在这里遗漏了一些简单的东西,但我无法弄明白。

谢谢!

* Lua Code *


function first ()
 -- Doesn't crash
 -- t = TestClass(1, 3)

 -- Crashes
 t = TestClass({1, 2, 3})

 print(t:get(0))
 print(t:get(1))
 print(t:get(2))
end

function second ()
 print("About to call collectgarbage...")
 collectgarbage()
 print("Done calling collectgarbage!")
end

function test ()
 first()
 second()
end

* C ++代码*


#include <iostream>
#include <lua.hpp>

#include <luabind/luabind.hpp>
#include <luabind/operator.hpp>

using namespace std;
using namespace luabind;

namespace luabind {
 template<typename ListType>
 struct default_converter<std::vector<ListType> > : native_converter_base<std::vector<ListType> > {
   static int compute_score(lua_State* L, int index) {
     return lua_type(L, index) == LUA_TTABLE ? 0 : -1;
   }

   std::vector<ListType> from(lua_State* L, int index) {
     std::vector<ListType> list;
     for (luabind::iterator i(luabind::object(luabind::from_stack(L, index))), end; i != end; ++i)
       list.push_back(luabind::object_cast<ListType>(*i));

     return list;
   }

   void to(lua_State* L, const std::vector<ListType>& l) {
     luabind::object list = luabind::newtable(L);
     for (size_t i = 0; i < l.size(); ++i)
       list[i+1] = l[i];

     list.push(L);
   }
 };
}

class TestClass {
public:
 TestClass(std::vector<int> v) : m_vec(v) {}

 TestClass(int b, int e) {
   for (int i = b; i <= e; ++i)
     m_vec.push_back(i);
 }

 int get(size_t i) const {
   return m_vec[i];
 }

private:
 std::vector<int> m_vec;
};

int main(int argc, char** argv) {
 if (argc != 2) {
   cout << "usage: " << argv[0] << " <scriptname>" << endl;
   return -1;
 }

 std::string scriptName = argv[1];
 lua_State* L = (lua_State*) lua_open();
 luaL_openlibs(L);

 open(L);

 module(L)
 [
   class_<TestClass>("TestClass")
     .def(constructor<std::vector<int> >())
     .def(constructor<int, int>())
     .def("get", &TestClass::get)
 ];

 if (luaL_loadfile(L, scriptName.c_str()) || lua_pcall(L, 0, 0, 0)) {
   cout << "Script error: " << lua_tostring(L, -1) << endl;
   return -1;
 }

 call_function<void>(globals(L)["test"]);

 lua_close(L);
 return 0;
}

1 个答案:

答案 0 :(得分:2)

是的,我明白了。事实证明,luabind完全没有任何问题,除了它的建造方式。在mac os x上的jam构建系统导致静态lua库与luabind共享库链接,当我链接我的最终二进制文件时,会导致重复的符号(和重复的静态变量)。虽然它没有链接整个 lua库,所以你仍然需要再次链接liblua.a。

用一粒盐解释这个解释,但这是我最好的猜测;我不是Mac OS X链接器如何工作的专家。我知道,当我静静地建造luabind时,一切正常。

所以,对于任何在mac中构建lubabind的人来说,静态构建。您必须修复的jam内置共享库还存在其他问题,例如@executable_path错误。静态构建很简单。