All Stories

崩溃问题分析

  这两天在抽空分析程序的崩溃记录,这些记录都按照版本号分别放在不同的文件夹中。早先exe文件的版本号并没有严格对应于svn revision号,周一时用一个修改PE资源的小程序搞定了这个事情,以后做这方面的事可要精确和省神多了。  今天分析到一个记录,印象中以前也有过类似的记录,一时没想起来,发现是一个线程函数数,对一个std::map调用find方法,结果在STL内部引起崩溃了。开始的时候,还以为是调用find方法时传入的参数有问题,引发了STL的某个未定义行为。于是另外写了个小程序简单验证了一下自己的猜想,结果不如自己所料。后来猜测要引用这个map的对象时,包含它的指针已经无效了。但为什么无效,我却也得不出什么结论。最后突然想到,从崩溃记录分析得到的最后堆栈信息中,看到是调用find方法后,find方法中取xtree的根节点引起的崩溃,那么是不是这个map对象本身就是有问题的了呢?灵光一闪,这个map对象是做为一个类的成员的,如果这个类的实例被销毁了,这个map对象自然也跟着被销毁,而这时如果再试图访问它,当然会有问题。  分析出来具体的原因,修改起来就比较容易了,在该类的实例被销毁时,应该通知那个线程马上结束,而且不要再试图去访问那些它的成员了。在修改这块代码的过程中,我应用了boost::thread,这大大简化和缩减了需要编写的代码。

最近Boost有点疯啊

  什么Boost.DirectX啊,Boost.Debug啊,Boost.Cppgui啊,越来越疯狂了哦!

我晕std::locale

  今天一个同事突然发邮件来说我的升级程序在生成文件列表时,给数字都以3个数字一段都加上了逗号,我狂晕!拿自己的debug代码试了试,发现果然如同事所言,看来是确定代码写得有问题了!  单步跟踪,最后发现我在把数字转换成字符串时,用了std::stringstream类的流输入方法,就变成那种样子了,稍微想了一下就明白过来了,以前一直都是没有逗号的,后来有过修改的地方也就是当时用ofstream写文件时,为了能支持中文的路径和文件名,在程序启动时调用了一句std::locale::global(std::locale(""));后来就有了这个问题。我狂分特啊,跟另外一个同事分享这个经验时,他还问我为什么不用boost::lexical_cast呢,其实据说boost::lexical_cast内部也是用的std::stringstream来转换的,哈哈!

总有一些自以为是的傻x

  说什么无法控制,说什么循环引用,说什么编译时间,都他妈的傻x。怎么不去关心一下CPU能不能控制,Windows能不能控制,还不是他妈的那儿老老实实用着。怎么不去用一下汇编,Fortran,狗日的哪来的循环引用。怎么不去用Debug自己输入二进制码,哪来的编译时间。  莫装B,装B被雷劈!

状态不好狂出错

  今天写代码,出了不少错,都是很低级的,状态不好啊。  先是连接一个MySQL数据库,从一个表中Select一些记录出来,死活没数据,还以为是SQL语句有问题,用其他客户端去运行,发现SQL语句是正常的。然后换了一条SQL语句,同样是Select的,发现又可以了,一步一步排查,发现是那个表中查不到数据,另外一个表中查得到数据,突然发现原来我连的MySQL地址不是我想要的那个!  接着是从XML格式的配置文件中读取配置信息,发现有的配置项好像怎么都读不出来,一直都是使用默认的值,后来才发现在判断值是否为空的时候,多写了个感叹号!  好不容易磕磕碰碰地调试通过了,编译了一个Release版本,用Inno Setup打了个包,放到目标机器上去运行,发现居然没反应,而且不巧的是我什么调试手段都没有,也没有什么日志。后来通过MessageBox发现,似乎配置信息读取又有问题了。然后发现如果是直接用Debug版本是正常的,于是想调试一下Release的,结果不知道应该设置什么选项,调试不了!只好通过OutputDebugString来打些信息出来。经过一番搏斗,发现原来我把装载配置文件的那条语句外面套了一个ASSERT,我狂晕!  以我现在的水平,状态好的时候,最多一个月也就能产1w行代码,而且代码质量还不能保证,唉,怎么才能让新写的代码跑得稳定呢!

准备使用Boost.Logging

  今天在Boost的邮件列表里看到有人在项目中使用Logging v2,这是在去年3月时提交Boost后review拒绝的一个库,当时我也略微关心过,因为一直在找一个好用的C++日志库,最后看到被拒绝了,我也就有点死心了,用起log4cxx来,其实发现log4cxx也不是那么好用,而且最近公司里用的时候发现似乎会有内存泄漏的问题。  看到邮件列表里那人对Logging的评价很高,我就心动了,它有一个优点是header only,这是我很喜欢的一点。其他的灵活性之类的我也没用过,也不好评价。不过我决定了,先在自己写的这些程序中试用一下。

史上最难用Win32 API

  啊,非SHFileOperation莫属!今天要实现个文件夹复制的特性,于是就想到这个API,可是很不幸,无论我怎么整,都报个1026错误!从网上找了一圈,发现代码根本一模一样的,人品问题啊!  后来在花费了不知道多少时间后,也许是1小时,也许更多,等不及了,花了10分钟自己用递归写了个函数来实现文件夹复制,我吐血三升!

boost svn中也有编译不过的代码

  回到家,习惯性地更新了一下boost svn中的代码,从来都最多只看一下哪些文件更新了,至于具体更新了什么内容,却从来没有关心过,也不是我能关心的。  然后整了一下自己写的一些代码。  再之后是继续整前几天放假时写的一个小程序,结果突然发现编译不过了!开始还怀疑该不会是VC出问题了吧,重启了一下VC,没用!于是看了一眼出错信息,定位到出错代码行,是boost::signals2中的一个叫signal_template.hpp的文件中。众所周知boost的代码只有超人才能看得懂,而我很幸运地不是超人,所以就看不懂啦!折腾了一阵,也没有办法,后来猛然看到这代码中明显是语法错误嘛!我猛烈地faint啊,原来超人也会犯错儿呀!尝试了一下把这语法错误修正,结果编译时报的是其他地方的错了,这我就不晓得是什么原因了。无奈之下,为了能正常编译我的程序,只好回退到之前一次提交的内容去了!  目瞪口呆!

鼠标手势算法

  今天看到一篇文章,讲鼠标手势算法,觉得有点意思。现在不少软件都有了鼠标手势支持,尤其是浏览器,几乎成了高级用户的标准配置了。  这算法分为4步。  一、过滤鼠标移动动作。如下图所示,这步过程把一连串的鼠标移动动作中幅度过小的动作过滤掉。这跟系统配置也有点关系,不同的配置下,记录鼠标移动的速率等量纲有所不同。   二、限制鼠标移动方向。如下图所示,对于简单的鼠标手势支持,只支持上下左右4个方向,就把其他方向的动作都归并到这4个方向中。一般就是比较一下上下方向和左右方向的差值,取大的那个作为最后的方向。   三、简化移动方向序列。如下图所示,这步非常简单,原本是右右上上右上上的方向序列,简化后变成右上右上了。   四、匹配和推演。这步是最困难的,表面是把夹杂在长距离移动动作中的短距离动作过滤掉。大概的做法是先把整个动作序列与一组预定义的序列匹配比较,如果匹配失败,就把这序列中最短幅度的动作过滤掉,再进行匹配,如此循环往复,直到最后匹配到为止。