2010-02-07 49 views
1

===編輯===問題在luabind與default_converter和表

這個問題實際上比這要簡單得多,任何包裝的函數,需要一個表是造成問題的原因。如果我包裝了一個需要luabind :: object的函數,並且使用table參數調用該函數,那麼gc將導致無效的free()。我開始認爲這可能是某種瘋狂的編譯/鏈接問題,因爲我編譯的Luabind dylib中有lua符號(導致這些符號的兩個副本,一個在該庫中,一個在我的二進制文件中)。也許我有一些lua靜態變量的副本或什麼?我可能只是在這裏抓住稻草。

===編輯===

使用luabind 0.9和MAC OS 4.2.1的gcc X 10.6

我看到有什麼能(也許?)是用從default_converter問題盧阿表。

我想在我的代碼中定義各種類列表類型的轉換器,特別是std :: vector。當我使用這樣一個default_converter將一個表傳遞給C++方法時,只要垃圾收集器被調用,lua就會在一個無效指針上使用free()崩潰。

我可能在這裏錯過了一些簡單的東西,但我無法弄清楚。

謝謝!

* Lua代碼*


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

Lua配備了這麼好的,簡單的C API,然而好心的程序員卻不斷受到來自'luabind'等工具的虛假承諾的誘惑。它所做的大部分工作是在你和真正非常簡單的界面之間插入複雜的模板元編程地獄。你可能會考慮直接使用Lua API。 – 2010-02-07 05:26:27

+5

我知道你正在努力幫助...但這並沒有幫助。除了這個問題,我實際上已經發現luabind非常簡單。鑑於在手動包裝所有東西之間進行選擇,並且僅僅使用luabind作爲*沒有* default_converter,我仍然會選擇luabind。或者,我可以手動包裝採用表格類型的方法。最終,我的計劃是手動開發lua包裝,但我仍然處於原型開發階段,如果手動推出我已經完成的工作,這將花費我10倍的時間。 – Kyren 2010-02-07 06:26:26

回答

2

是啊,我想通了。結果發現,除了它的建造方式,luabind根本沒有任何問題。在mac os x上,果醬構建系統會將靜態lua庫鏈接到luabind共享庫中,當我鏈接最終的二進制文件時會導致重複的符號(以及重複的靜態變量)。它沒有連接lua庫中的整個,所以你仍然需要再次鏈接liblua.a。

用一粒鹽做這個解釋,但這是我最好的猜測;我不是Mac OS X鏈接程序工作方式的專家。我知道,當我靜態構建luabind時,一切正常。

因此,對於在mac中構建lubabind的任何人,靜態構建。還有其他問題需要修復,例如@executable_path錯誤。靜態構建很簡單。