<转>LuaTinker的bug和缺陷
LuaTinker的bug和缺陷
LuaTinker是一套还不错的C++代码和Lua代码的绑定库,作者是韩国人Kwon-il Lee,作者应该是参考了LuaBind后,为了简化和避免过重而实现的。其官网在http://gpgstudy.com/gpgiki/LuaTinker ,但可惜全部是韩文的,而最新的代码可以在Git上下载,https://github.com/zupet/LuaTinker 。对比LuaBind,LuaPlus这类库,其实现非常非常非常非常非常轻,大约只有1000多行,至少给了你一个机会,去了解和改写部分功能,所以其在国内也有不少群众基础。而且其轻薄的身材也让剖析一下一个脚本粘合层是如何工作成为了可能。
但另外一方面LuaTinker的bug数量并不在少数。也有不少同学曾经零散的提出来过。这儿只是做个总结,另外感谢fergzhang同学。很多问题都是他帮忙指出的。
- BUG(错误)
第一个问题,int64_t 数据的比较是错误的,完全没有考虑符号位的情况嘛。
static int lt_s64(lua_State *L)
{
//完全没有考虑符号位的情况,居然用memcmp
lua_pushboolean(L, memcmp(lua_topointer(L, 1), lua_topointer(L, 2), sizeof(long long)) < 0);
return 1;
}
第二个问题,在处理类成员的修改函数(__newindex)时,没有考虑要处理父类成员的,而LuaTinker是支持继承的,而且int lua_tinker::meta_get(lua_State *L) (对应__index)也是支持。这应该是作者的一个疏漏。

int lua_tinker::meta_set(lua_State *L)
{
enum_stack(L);
lua_getmetatable(L, 1);
lua_pushvalue(L, 2);
lua_rawget(L, -2);
enum_stack(L); if (lua_isuserdata(L, -1))
{
user2type<var_base *>::invoke(L, -1)->set(L);
}
else if (lua_isnil(L, -1))
{
//这儿没有调用invoke_parent(L)处理父类的情况
lua_pushvalue(L, 2);
lua_pushvalue(L, 3);
lua_rawset(L, -4);
}
lua_settop(L, 3);
return 0;
}

第三个bug,使用I64d这种过时的标签,I64d应该是微软很老很老很老的一个格式化字符串标签,而且完全不具备可移植性。应该改为%lld。

static int tostring_s64(lua_State *L)
{
char temp[64];
sprintf_s(temp, "%I64d", *(long long*)lua_topointer(L, 1));
lua_pushstring(L, temp);
return 1;
}

第4个bug,var_base基类的析构函数没有写virtual

struct var_base
{
//原来的析构函数没有写virtual
virtual ~var_base() {};
virtual void get(lua_State *L) = 0;
virtual void set(lua_State *L) = 0;
};

第5个bug,table的3个构造函数中有一个没有增加引用计数,这个bug在网上很多同学都指出过。

lua_tinker::table::table(lua_State* L, const char* name)
{
lua_pushstring(L, name);
lua_gettable(L, LUA_GLOBALSINDEX); if(lua_istable(L, -1) == 0)
{
lua_pop(L, 1); lua_newtable(L);
lua_pushstring(L, name);
lua_pushvalue(L, -2);
lua_settable(L, LUA_GLOBALSINDEX);
} m_obj = new table_obj(L, lua_gettop(L));
//原来的代码没有这段,缺少增加引用计数处理
m_obj->inc_ref();
}

, CSDN的ainn_pp也写过这个问题,参考:http://blog.csdn.net/ainn_pp/article/details/2773855
- 缺陷
LuaTinker也有很多缺陷和不足,
第一个不足,各种函数参数的支持个数参差不齐。LuaTinker的写的时间应该比较早,没有C++ 11的模版变参(Variadic Template)的支持,所以只能用写多个模版函数(类)的方式解决多模板参数问题。但LuaTinker一方面写的参数个数很少,一方面LuaTinker的个个地方支持的参数个数数量完全不统一,3个,4个,5个的都有。其实这部分最好用C++ 11的(Variadic Template)重写。
第二个缺陷是个硬伤,LuaTinker对Lua 协程的支持,用了一个很费力,但又不讨好的方式。你必须把协程的第一个参数定义为lua_State *L,而且返回值必须是lua_yield(L, 0)。这样的限制,大大限制了使用。

//第一个参数必须是(lua_State *L
int TestFunc2(lua_State *L, float a)
{
printf("# TestFunc2(L,%f) is invoke.\n", a);
//返回的地方必须是调用lua_yield
return lua_yield(L, 0);
} class TestClass
{
public: //类函数也一样
int TestFunc2(lua_State *L, float a)
{
printf("# TestClass::TestFunc2(L,%f) is invoke.\n", a);
return lua_yield(L, 0);
}
};

而如果其实在其函数的封装上加以区分,自己在最后调用lua_yield,这就可以避免这个麻烦。这个实现实在让我没有多大胃口。
第三个地方是,是对引用变量(参数),注册的问题,其实这个也不是LuaTinker的问题,而是C++模版的问题,C++的自动模版函数参数推导是存在一些潜规则的。其中有一个就是左值变换,在 《CUJ:高效使用标准库:显式函数模板参数申明与STL》 一文中有比较清晰的解释。如下示例:
//下面的写法是无法得到引用的,必须显式指定参数。
//lua_tinker::set(L, "ref_a", ref_a); //显式声明引用参数
lua_tinker::set<TestA &>(L, "ref_a", ref_a);
第4个问题就是,模版处理中,对于cv(const volatile)的去除掉处理也并不理想。Lua内部对于外部的class的注册是使用函数class_add,也就是用一个名称关联一个Lua的meta table,在类的后面的使用中,通过class_name<T>::name函数取得类名,但实际中,很多时候T是带有const 或者 volatile的修饰符的。包括,LuaTinker在部分处理中去掉了const,但很多地方又忽略问题,编译器不会认为classA和const class A是一个东东的。所以结果就是有时候无法让你的userdata找到对应的meta table。

lua_tinker::class_add<TestA>(L, "TestA");
lua_tinker::class_con<TestA>(L, lua_tinker::constructor<TestA>); //用模板函数辅助帮忙实现一个方法,可以通过class 找到对应的类名称(注册到LUA的名称),
template<typename T>
struct class_name
{
// global name
static const char *name(const char *name = NULL)
{
static char temp[256] = "";
if (name)
{
strcpy_s(temp, name);
}
return temp;
}
};

fergzhang同学,针对LuaTinker的一些bug修正做了一个版本。同时好像支持了5.2的版本,他放在了https://github.com/zfengzhen/lua_tinker_5.2.git
而我自己针对上面的问题实现了一套LuaTie的库,没有时间,有时间整理出来。内部用C++ 11的特性做了一些改写。
https://github.com/sailzeng/zcelib/blob/master/src/commlib/zcelib/zce_script_lua_tie.cpp
https://github.com/sailzeng/zcelib/blob/master/src/commlib/zcelib/zce_script_lua_tie.h
工程内部是有测试的例子的,但没有整理出来,看起来比较麻烦。等后面整理出来再写一篇介绍的文章把。
最后,虽然我在挑刺,但还是再次表达一下对 LuaTinker作者Kwon-il Lee的感谢,这套代码帮助我了解了如何绑定脚本以及了解MPL的一些基本知识.而且坦白讲LuaBind是和Boost绑定的,能费力从这些代码中简化出LuaTinker(阅读Boost代码实在谈不上愉快),真的是一件很了不起的事情,LuaTinker的作者可能更明白轻对于代码的好处,Kwon-il Lee在主页上有一段说明其为什么没有支持LuaBind所支持的重载,而我也认为一个优秀的库始终要是简单的。
【本文作者是雁渡寒潭,本着自由的精神,你可以在无盈利的情况完整转载此文档,转载时请附上BLOG链接:http://www.cnblogs.com/fullsail/,否则每字一元,每图一百不讲价。对Baidu文库和360doc加价一倍】
<转>LuaTinker的bug和缺陷的更多相关文章
- LuaTinker的bug和缺陷
LuaTinker的bug和缺陷 LuaTinker是一套还不错的C++代码和Lua代码的绑定库,作者是韩国人Kwon-il Lee,作者应该是参考了LuaBind后,为了简化和避免过重而实现的.其官 ...
- 测试基础:Bug管理那些事_20160910
1.bug由来 虫子爬进主机引起继电器短路,导致机器故障.真正的缺陷是:主机散热孔少装了块金属丝,这样才能防止虫子爬到主机. 2.什么是bug? bug是缺陷的一种表现形式,而一个缺陷是可以引发多种b ...
- bug的处理流程
又属于一篇普及文,希望自己在被各种技术吸引的同时,能时常来整理和总结软件测试最基本的知识. 从刚工作时接触的第一个缺陷管理工具禅道,到redmine.JIRA.bugzilla ,再到现在的QC,当然 ...
- Linux Kernel 2.6.28 以上有BUG,系统运行第208.5天down机
简介: 业务服务器有一台服务器出现意外down机,服务器ping 不通.无法登陆,本想通过公司KVM系统登陆系统重启解决,登陆KVM后发现系统屏幕打印大量的内核错误,KVM无法使用.无法发送重启服务器 ...
- bug管理工具
1..禅道 禅道项目管理软件(简称:禅道)集产品管理.项目管理.质量管理.文档管理.组织管理和事务管理于一体,是一款功能完备的项目管理软件,完美地覆盖了项目管理的核心流程. 禅道的主要管理思想基于国际 ...
- BUG 的生命周期
BUG 的生命周期 Bug-->软件程序的漏洞或缺陷 Bug 的类型:代码错误.设计缺陷.界面优化.性能问题.配置相关.安装部署.安全相关.标准规划.测试脚本....其他(功能类.界面类.性能类 ...
- 测试基础【第六篇】bug要素及其生命周期
bug的要素 为了让开发人员更准确.更快的看懂Bug,测试需要按照一定的规范提交bug. 缺陷id:一般由缺陷管理系统自动生成: 缺陷标题:概要描述缺陷: 发现人:一般是缺陷管理系统自动获取当前用户: ...
- bug的全部
BUG 的生命周期 BUG 的生命周期 Bug-->软件程序的漏洞或缺陷 Bug 的类型:代码错误.设计缺陷.界面优化.性能问题.配置相关.安装部署.安全相关.标准规划.测试脚本....其他(功 ...
- Elasticsearch Java 虚拟机配置详解
Elasticsearch对Java虚拟机进行了预先的配置.通常情况下,因为这些配置的选择还是很谨慎的,所以你不需要太关心,并且你能立刻使用ElasticSearch. 但是,当你监视ElasticS ...
随机推荐
- 【思维】Stacks of Flapjacks
[UVa120] Stacks of Flapjacks 算法入门经典第8章8-1 (P236) 题目大意:有一个序列,可以翻转[1,k],构造一种方案使得序列升序排列. 试题分析:从插入排序即可找到 ...
- 【贪心】【后缀自动机】XIII Open Championship of Y.Kupala Grodno SU Grodno, Saturday, April 29, 2017 Problem E. Enter the Word
题意:给你一个串,让你从左到右构造这个串,一次操作可以直接在当前串后面添加一个任意字符,或者拷贝当前串的任意一个子串到当前串的后面.问你最少要多少次操作才能构造出这个串. 从前向后贪心,从当前已构造的 ...
- bzoj 4401: 块的计数
4401: 块的计数 Description 小Y最近从同学那里听说了一个十分牛B的高级数据结构——块状树.听说这种数据结构能在sqrt(N)的时间内维护树上的各种信息,十分的高效.当然,无聊的小Y对 ...
- [HDU3756]Dome of Circus
题目大意: 在一个立体的空间内有n个点(x,y,z),满足z>=0. 现在要你放一个体积尽量小的圆锥,把这些点都包住. 求圆锥的高和底面半径. 思路: 因为圆锥里面是对称的,因此问题很容易可以转 ...
- SpringBoot使用Gradle构建war包
Spring Boot默认将应用打包成可执行的jar包.有时候需要打包成war包部署在tomcat等容器.下面简单介绍下打包的步骤. 一.修改gradle.build文件 1.1 添加如下配置 app ...
- 那些年我们踩过的坑-NSTimer
昨天下午工作的时候遇见一个这样的需求,网络请求失败后把请求数据保存到本地,并自动重发3次,时间间隔是10秒,如果3次后还失败的话,下一次启动这个接口的时候,把新数据和保存在本地的数据都要发送,刚开始以 ...
- 【shiro】使用shiro,点击页面请求总是302状态码
解决方法: 配置shiro中,将要求放过的地址后面加上后缀,这里是.htmls 因为web.xml中配置所有的页面都是放过的
- CSS -- 绝对相对定位
relative相对于自己原来的位置进行相对定位absolute相对于最近的父级元素进行定位fixed始终相对于浏览器窗口进行对位 顺便说一下,fixed就是特殊的absolute.
- [转]SSIS OLE DB Source中执行带参数的存储过程
本文转自:http://www.cnblogs.com/michaelxu/archive/2009/10/21/1587450.html 问题描述:执行一个存储过程得到一个多条记录的结果集,然后循环 ...
- 用于OpenRISC的Makefile示例
#* #*********************************************************************************************** ...