日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

[zz]为 Lua 绑定 C/C++ 对象

發布時間:2023/12/9 c/c++ 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [zz]为 Lua 绑定 C/C++ 对象 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自: http://blog.codingnow.com/2013/01/binding_c_object_for_lua.html

?

如何綁定 C/C++ 對象到 Lua 里?通常是創建一個 userdata ,存放 C/C++ 對象指針,然后給 userdata 添加元表,用 index 元方法映射 C/C++ 中的對象方法。

也有另一個手段,直接用 lightuserdata 保存 C/C++ 對象指針放到 Lua 中,在 Lua 中創建一個 table 附加元表來來包裝這個指針,效果是類似的。區別在于對象生命期的管理方式有所不同。就這個問題,幾年前我寫過一篇 blog 。

綁定 C/C++ 對象到 Lua 里的設計難點往往在這個正確的生命期管理上。因為 C/C++ 沒有 GC 系統,依賴手工管理資源;而 Lua 則是利用 GC 做自動回收。這兩者的差異容易導致在 Lua 中的對象對應的 C/C++ 對象已經銷毀而 Lua 層不自知,或 Lua 層中已無對象之引用,而 C/C++ 層中卻未能及時回收資源而造成內存泄露。

理清這個問題,首先你要確定,你打算以 Lua 為主干來維護對象的生命期,還是以 C/C++ 層為主干 Lua 部分只是做一些對這些對象的行為控制。

我個人主張圍繞 Lua 來開發,C/C++ 只是寫一些性能相關的庫供 Lua 調用,即框架層在 Lua 中。這樣,C/C++ 層只提供對象的創建和銷毀函數,不要用 C 指針做對象的相互引用。Lua 中對象被回收時,銷毀對應的 C 對象即可。

但是,也有相當多的項目做不到這點。Lua 是在后期引入的,之前 C/C++ 框架層中已做好了相當之復雜的對象管理。或者構架師不希望把腳本層過多的侵入引擎的設計。

那么,下面給出另一個方案。

我們將包裝進 Lua 的 C 對象稱為 script object ,那么只需要提供三個函數即可。

int script_pushobject(lua_State *L, void * object) {void **ud;if (luaL_newmetatable(L, "script")) {// 在注冊表中創建一個表存放所有的 object 指針到 userdata 的關系。// 這個表應該是一個 weak table ,當 Lua 中不再存在對 C 對象的引用會刪除對應的記錄。lua_newtable(L);lua_pushliteral(L, "kv");lua_setfield(L, -2, "__mode");lua_setmetatable(L, -2);}lua_rawgetp(L,-1,object);if (lua_type(L,-1)==LUA_TUSERDATA) {ud = (void **)lua_touserdata(L,-1);if (*ud == object) {lua_replace(L, -2);return 0;}// C 對象指針被釋放后,有可能地址被重用。// 這個時候,可能取到曾經保存起來的 userdata ,里面的指針必然為空。assert(*ud == NULL);}ud = (void **)lua_newuserdata(L, sizeof(void*));*ud = object;lua_pushvalue(L, -1);lua_rawsetp(L, -4, object);lua_replace(L, -3);lua_pop(L,1);return 1; }

這個函數把一個 C 對象指針置入對應的 userdata ,如果是第一次 push 則創建出新的 userdata ,否則復用曾經創建過的。

void * script_toobject(lua_State *L, int index) {void **ud = (void **)lua_touserdata(L,index);if (ud == NULL)return NULL;// 如果 object 已在 C 代碼中銷毀,*ud 為 NULL 。return *ud; }

這個函數把 index 處的 userdata 轉換為一個 C 對象。如果對象已經銷毀,則返回 NULL 指針。 在給這個對象綁定 C 方法時,應注意在 toobject 調用后,全部對指針做檢查,空指針應該被正確處理。

void script_deleteobject(lua_State *L, void *object) {luaL_getmetatable(L, "script");if (lua_istable(L,-1)) {lua_rawgetp(L, -1, object);if (lua_type(L,-1) == LUA_TUSERDATA) {void **ud = (void **)lua_touserdata(L,-1);// 這個 assert 防止 deleteobject 被重復調用。assert(*ud == object);// 銷毀一個被 Lua 引用住的對象,只需要把 *ud 置為 NULL 。*ud = NULL;}lua_pop(L,2);} else {// 有可能從未調用過 pushobject ,此時注冊表中 script 項尚未建立。lua_pop(L,1);} }

這個函數會解除 C 對象在 Lua 中的引用,后續在 Lua 中對這個對象的訪問,都將得到 NULL 指針。


這些代碼是在我寫這篇 blog 的同時隨手寫的,并未經過嚴格測試。它們也有許多改進空間,比如給 C 對象加入類型,對 userdata 做更嚴格的檢查,等等。

總結

以上是生活随笔為你收集整理的[zz]为 Lua 绑定 C/C++ 对象的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。