tolua++實現分析

項目正在使用cocos2dx的lua綁定,綁定的方式是tolua++。對大規模使用lua代碼信心不是很足,花了一些時間閱讀tolua++的代碼,希望對綁定實現的瞭解,有助於項目對lua代碼的把控。從閱讀結果上來看,起碼在內存管理上,幫助還是很大的。


1.tolua++如何將c++對象導入到lua裏

tolua++爲每一個傳入lua的對象建立一個userdata,userdata的值,是c++對象的地址。userdata的metatable,是一個tolua++建立的,記錄了userdata對應c++類型信息的表格,包括導出的成員變量、成員函數等信息。

對於成員變量的讀取賦值,tolua++是在metatable裏新建了.get和.set兩個表。兩個表裏分別存儲了以變量名爲鍵,以讀取設置c函數爲值的表項。在metatable的__index和__newindex裏,以變量名爲鍵,從.get和.set表裏取得讀取設置函數並調用。


對於成員函數的調用,只需要以函數名爲鍵,函數爲值,存儲在metatable裏就好了。


傳入c++對象的tolua++函數是tolua_pushusertype。一般情況下,第一次使用這個函數將一個c++對象push到lua堆棧上時,纔會新建userdata。tolua++會以c++對象地址爲鍵,userdata爲值,將鍵值對存儲在tolua_ubox表裏。下次推入同樣的c++對象時,從這個表裏取出userdata推入堆棧即可。

—————————————————


2.tolua++如何處理類型的繼承

父類的metatable,是子類metatable的metatable。這樣調用父類方法時,就會去父類的metatable裏查找了。

tolua++還維護了一個tolua_super表,這個表以c++類型的metatable爲鍵,以一個表格爲值。這個值表格以類型名稱爲鍵,以true爲值,記錄了metatable對應c++類型的父類有哪些。這個表格可以用來幫助判斷對象是否是某一個類型(子類實例也可以認爲是父類類型)


—————————————————


3.tolua++如何管理對象的生命週期

一般情況下,當lua裏對c++對象的引用變量可以被垃圾回收時,tolua++只是簡單的釋放userdata佔用的4字節指針地址內存。但是也可以通過綁定或者代碼指定的方式,讓tolua++真正釋放對象所佔內存。

綁定的方式,是指在將c++類型構造函數使用tolua++導出到lua裏時,tolua++會自動生成new_local方法。如果在lua代碼裏,用這個方法新建對象時,tolua++會調用tolua_register_gc方法,指明回收對象時回收對象內存。

在c++代碼裏,使用tolua_pushusertype_and_takeownership;在lua代碼裏,使用tolua.takeownership,都可以達到同樣的目的。

對於這些指定由tolua++回收內存的對象,如果其類型的析構函數也通過tolua++導出了,則在回收內存時,會通過delete運算符,調用對象的析構函數。否則只會使用free方法回收。

tolua_register_gc方法,做的事情,是以對象指針爲鍵,以對象metatable爲值,將鍵值對存儲在tolua_gc表裏。在對象類型的metatable表的__gc方法裏,tolua++會檢查tolua_gc表是否包含以這個地址爲鍵的表項。包含的話纔會進行上述的內存回收工作。


4.其它

有的時候,在lua裏取得一個c++對象後,我們想賦給它一些只在lua環境下有意義的屬性。或者,我們想在lua裏擴展一個c++類。tolua++也提供了實現這種需求的機制。

tolua++在LUA_REGISTRY裏維護了一張tolua_peers表。這張表以表示c++對象的userdata爲鍵,以一張表格t爲值。t裏面就記錄了這個對象在lua裏擴展的屬性。


cocos2dx並沒有完全使用tolua++的方式,而是自己進行了一些修正。下篇博客應該會記錄修正的原因和方式,並介紹一些cocos2dx lua bind特定的東西。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章