网站面试通知表格怎么做,.net 网站开发教程,网站建设 客户,模板建站网页转载自#xff1a; http://blog.codingnow.com/2013/01/binding_c_object_for_lua.html 如何绑定 C/C 对象到 Lua 里#xff1f;通常是创建一个 userdata #xff0c;存放 C/C 对象指针#xff0c;然后给 userdata 添加元表#xff0c;用 index 元方法映射 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 做更严格的检查等等。