2016-02-05 54 views
1

我相信你們中的一些人可能會遇到這個問題。我有一個用C++編寫的叫做矩陣的用戶數據對象,通常使用運算符重載方式,比如。lua userdata按值傳遞

CMatrix<T>& operator=(const CMatrix<T>& b); 
CMatrix<T>& operator=(const T& rhs); 

在C++中,當我創建兩個矩陣說AB和使A=B則A和B可被用作兩個獨立的對象。然而,在Lua寫A=B並更改B的任何屬性時,A也會發生變化。

從Lua手冊中可以看出,據說Lua通過引用來解釋上述行爲來做userdata的分配。但是,如何使A=B按值傳遞,以便在B更改時A不受影響。

由於事實上,我想使分配A=B通過引用傳遞這的確是非常快和Matlab的呢,但是當我設置的B屬性的第一次,我想B進行獨立創作這是我的Matlab實踐,因爲我可以從Matlab的內存使用情況跟蹤。

如果這是可能的,它是在C++內部還是在lua包裝代碼的某個地方完成的?任何示例代碼都會很棒。

編輯1:這裏是我的想法,我不知道這是否會在所有的工作,或者如果這樣不夠快

typedef struct luaelement 
{ 
    int type; 
    std::string name; 
    void* addr; //newly added field 
    bool isRef; //newly added 
} luaelement; 

glbLuaElementSet=new set<luaelement,comparenocaseforluaelement>(); 

int l_newindex(lua_State* L) 
{ 
    luaelement element; 
    const char* key=lua_tostring(L,-2); 
    string str=key; 
    element.name=key; 
    element.type=lua_type(L,-1); 
    //How can I get the address, maybe a metamethod named address 
    glbLuaElementSet->insert(element); 
    lua_rawset(L,1); 
} 

void l_registermetamethod(lua_State* L) 
{ 
    lua_getglobal(L,"_G"); 
    lua_createtable(L, 0, 1); 
    lua_pushcfunction(L, l_newindex); 
    lua_setfield(L, -2, "__newindex"); 
    lua_setmetatable(L, -2); 
} 

現在用glbLuaElementSet變量和l_newindex元方法我可以跟蹤在插入的所有變量全球_G表。我正計劃通過檢查void*地址來實現並查看是否存在對現有userdata變量的引用。我不確定這是否真的有效,如果值得在性能方面付出努力。

+0

你最後的部分是嚴格的C++問題;你在談論什麼叫做「寫時複製」語義。除非你的矩陣對象很大,否則對於一個值類型通常是一個糟糕的主意。當然,它聽起來很快。但隨着現代移動語義和複製elision,你會發現自己沒有做太多的對象複製。它也使得你的對象非線程安全,或者需要你鎖定互斥鎖來訪問它們。 –

+2

「如何讓A = B按值傳遞,以便在B發生變化時A不受影響。」 - 這就像問:「我怎樣才能讓MyClass c = new MyClass();'在C++中工作,就像它在Java中一樣?」 - 即使你可以(而且我認爲你不能),這不是一個好主意。 – immibis

+0

我只是有一個方法克隆它的矩陣。 – warspyking

回答

4

但是,如何讓A = B按值傳遞,以便在B發生變化時A不受影響。

你不能。

記住:Lua是動態輸入。所以雖然AB恰好現在存儲您的矩陣類型,但稍後去A = 1也是很好的。現在,A存儲一個整數。

C++和Lua是非常不同的語言。在C++中,變量是對象或對象的引用(指針是指針類型的對象)。每個變量只會保存它開始的對象。存儲在該對象中的值可以更改,但該對象本身存在並具有由所討論的變量的生存期定義的生命週期。

在Lua中,變量只是一個對象可以存儲在其中的框。該框與它當前碰巧存儲的對象沒有關係;任何箱子可以容納任何物體。並且在任何時候,您都可以將該框中的內容與其他框中的對象進行交換。

你不能干涉將一個變量拷貝到另一個變量中(通常,你可以做metatable體操,但只適用於該表的成員,局部變量永遠不會受到影響)。這就是Lua如何作爲一種語言工作的。C++變量是對象; Lua變量是存儲盒。最好接受你不能在Lua中編寫C++風格的代碼,而是專注於在Lua中編寫Lua風格的代碼。

所以,如果你想創建一個對象的副本,你必須創建該對象的副本明確


這裏是我的想法,我不知道這是否會在所有的工作,或者如果這樣足夠

快,不會有幾個原因的工作。

首先,你正在應用metatable到全局表本身,這通常是...粗魯。

其次,即使你的代碼工作,它不會對如此簡單的東西的工作:

globalVar = {} --Perfectly legal to set a table inside the global table. 
globalVar.value = A 
globalVar.value = B --Will not alert your copying code. 

__newindex元方法是不遞歸。它不能在表格的層次結構中上下移動。所以存儲在全局表中的表格仍然可以更改其成員。

不要試圖讓Lua變成它不是的東西。使用你有的語言,而不是你想要的語言。

+0

可能最好的方法是添加一個拷貝metamethod ... – macroland

+0

Lua中的表和函數和userdatas被一個變量引用*。數字,字符串,布爾值和零,然而*持有*變量。 – warspyking

+0

@macroland:那不行。 –