google的广告匹配算法其实也挺搞的
write by 九天雁翎(JTianLing) -- www.jtianling.com
讨论新闻组及文件
大家都知道google的广告吧。。。那属于通过匹配你浏览的网页中的关键字提供给你你可能最需要的广告,google的广告一向以此为卖点,或者说是优点。
今天在看一个关于Python的网站,结果google给我匹配出了一个搞笑的广告-_-!一个卖蟒蛇皮的手袋的网站。。。Python handbag。。。。晕,本来截了图了,但是csdn网站照常出了问题,图片不能上传,以后又机会再补吧。
呵呵,计算机的程序的极限还远远没有到。。。。
write by 九天雁翎(JTianLing) -- www.jtianling.com
阅读全文....
今天从各类网站,辗转跳转,从《梦断代码》跟到《新机器的灵魂》,突然在
《新机器的灵魂》IT业魂在何方?
文中,看到了一句话," 计算机业最振奋也是最残酷的特性就是喜新厌旧。",很感叹。。。。呵呵,大家自由想象。。。。。。。。。起码从编程语言上来想。。。此话实在不假,虽然C也坚持了这么多年了。
各类网站,新特性等等,喜新厌旧,无孔不入,不过,就是这个新。。。不也是代表着创新及激情吗?。。一句话,也可以引发人无限的思考。
"
但疯狂的节奏下,一些内在的东西是弥久的,甚至是永恒的。毕竟任一行业,其真正的主角都是人,而人恐怕是世界上最难升级的事物。写于22年前的《新机器的灵魂》无疑是一本经得起时间锤打的经典。它讲述了一群忘我工作的电脑技术人员,制造一台新型计算机的动人过程。可以说,本书定义了计算机业整整一个时代的灵魂和精神。尽管业内技术2年一变,人物5年一换,但这个产业的问题和驱动力与10年、20年前相比并无两样,只是不同的公司扮演着不同的角色而已。无论是后来的PC之火,还是互联网浪潮,都没有脱离贯穿这个产业数十年的本质。
"
有时看到一些文字真的很感叹。。。。为啥人家水平那么高呢?。。。。。。呵呵,学习了。
阅读全文....
被雷到了,号称没有思想负担的C语言,在号称经典的freeBSD的源代码中的一段红黑树实现的源代码。
http://www.freebsd.org/cgi/cvsweb.cgi/~checkout~/src/lib/libc/stdlib/rb.h?rev=1.4.2.1;content-type=text%2Fplain
假如这样叫经典。。。。让我去死吧。大家都去拜读freeBSD的源代码吧,以后都能成为神一样的人物。
阅读全文....
In addition to alternative list implementations, the library also offers other tools such as the bisect module with functions for manipulating sorted lists:
>>> import bisect
>>> scores = [(100, 'perl'), (200, 'tcl'), (400, 'lua'), (500, 'python')]
>>> bisect.insort(scores, (300, 'ruby'))
>>> scores
[(100, 'perl'), (200, 'tcl'), (300, 'ruby'), (400, 'lua'), (500, 'python')]
摘自:Python 2.6.1的文档,Brief Tour of the Standard Library – Part II章,Tools for Working with Lists节
呵呵,很明显可以看出Guido van Rossum的意图,以scores来表示含义,然后分别给了perl 100分,tcl 200分, ruby 300分, lua 400分,然后给了其创造的语言python 最高的500分:)
其他的都还能理解。。。。。不过ruby在其心中排在lua之后,实在有点让ruby阵营的人抓狂-_-!呵呵,虽然个人没有学过ruby,仅学过lua。。。。。。
呵呵,纯YY一下,这是偶然从文档中查资料的时候翻出来的:)
阅读全文....
程序员平时都是木讷的,但是谈到计算机或者程序的时候简直就是天才—兼借题发挥,谈谈语言及工具的选择
write by 九天雁翎(JTianLing) -- www.jtianling.com
讨论新闻组及文件
程序员们对各类事物的敏感度可能都不够,但是对于计算机和程序语言的敏感度实在太高,所以,在这个他们赖以为生的领域,他们的聪明才智发挥的是若此的淋漓尽致。
最近看到CSDN上的
《语录:101条伟大的计算机编程名言》,觉得很有意思:)
其中有很多,是真的属于程序员才能理解的幽默:
最能让人会心一笑的是61条:
61、我想微软之所以把它叫做.Net,是因为这样它就不会在Unix的目录里显示出来了.(Oktal)
不理解的兄弟。。。。和你解释了也就没有效果了。
也有很多的确是属于经验之谈:
32、好的软件的作用是让复杂的东西看起来简单.(Grady Booch,UML创始人之一)
62、There is no programming languageno matter how structuredthat will prevent programmers from making bad programs.(Larry Flon)
(这是唯一文章中没有翻译的,不知道为啥漏了,意思是无论结构多好的程序语言都不能阻止程序员写出垃圾程序。)
75、好代码本身就是最好的文档.(Steve McConnell)
另外,因为国外对s e x这种事情看的比较普通,所以例子中不乏相关的类比:
70、说Java好就好在运行于多个操作系统之上,就好像说肛 交好就好在不管男女都行.(Alanna)
73、软件就像性事:免费/自由更好.(Linus Torvalds)
程序语言是程序员的信仰,其圣战从未停止过:
57、只有两种编程语言:一种是天天挨骂的,另一种是没人用的.(Bjarne Stroustrup,C++之父)
58、PHP是不合格的业余爱好者创建的,他们犯做了个小恶;Perl是娴熟而堕落的专家创建的,他们犯了阴险狡诈的大恶.(Jon Ribbens)
微软作为世界软件世界的实际霸主,相关的也不少,除了.net那一条,我觉得还比较有意思的是:
18、微软有出了个新版本,Windows XP,据大家说是'有史以来最稳定的Windows', 对我而言, 这就好像是在说芦笋是'有史以来发音最清脆的蔬菜一样' (Dave Barry)
调试永远是占用着程序员绝大部分时间:。。。。。
14、我终于明白'向上兼容性'是怎么回事了.这是指我们得保留所有原有错误.(Dennie van Tassel)
84、如果调试是除虫的过程,那么编程就一定是把臭虫放进来的过程.(Edsger W. Dijkstra)
为了增加主题的契合度,我还引用一些国内有意思的例子,某年某月,当大牛开始贬低C++的时候,国内程序员突然牵扯到C++,Python上的争吵:
d 发表于2007年9月11日 11:59:29 IP:举报
C++还在讨论String的时候.Python已经做好了项目在喝酒了.我也有一句.python在为开发一个操作系统无能为力的时候.C++已经在喝COFI了,晕.
gussing 发表于2007年9月11日 12:21:01 IP:举报
是啊,可以喝咖啡,多爽
python 程序员喝了十年咖啡,c程序员熬了十年夜,后来在一次聚会上他们相遇了,python还在喝咖啡,c程序员则买了一艘豪华游艇准备出海旅游。python 程序员一脸兴奋的说:老兄,知道吗,python又出新库了!c程序员也一脸兴奋,说:当然知道,那正是我带领的一个团队开发的。
irplay 发表于2007年9月11日 12:45:43 IP:举报
python什么垃圾啊...高不成低不就的语言都要淘汰.
hehe 发表于2007年9月11日 13:20:52 IP:举报
gussing 发表于2007-09-11 12:21:00 IP: 220.248.25.*
是啊,可以喝咖啡,多爽
python 程序员喝了十年咖啡,c程序员熬了十年夜,后来在一次聚会上他们相遇了,python还在喝咖啡,c程序员则买了一艘豪华游艇准备出海旅游。python 程序员一脸兴奋的说:老兄,知道吗,python又出新库了!c程序员也一脸兴奋,说:当然知道,那正是我带领的一个团队开发的。
--------------------------------------------
一百个python程序员都在喝咖啡,一百个c程序员中只有一个买了游艇,剩下99个还在加班
笑死 发表于2007年12月28日 1:32:01 IP:举报
刚喝完咖啡,忽然客户过来说:"太慢了,我去找人重新开发.我们的合作到此为止啦".
呵呵,C++程序员对于Python运行速度的攻击,Python程序员对于C++开发效率的攻击都是如此的尖锐并且有思想:)很有意思,我印象深刻,好不容易翻出来啊。。。。。
说到圣战:。。。VIM与Emacs的圣战被誉为从计算机发明那天就开始,计算机历史上持续最长时间的圣战:)有很多相关资料,这里是一个
《EMACS 对 vi:永无止境的圣战》
。。。无奈的是。。。我作为靠C++谋生,业余对Python很感兴趣,并且无论在Linux下,Windows下都使用着VIM的家伙,几大圣战的讨论我都是被攻击的当事人-_-!(因为攻击者肯定都是全面积覆盖)
其实。。。从使用者的角度来说,没有东西是完美的,但是都存在选择,当年也在EMACS和VI中选择,最后我发现我要的仅仅是一个在任何时候都可以使用的方便的文本编辑工具的时候,我选择了VIM,虽然也有被那句很经典的话打动的意思:EMACS的程序员都希望增加一个脚踏板。。。呵呵
当我觉得我需要是一种通用的编程语言,但是却要足够的接近底层的时候,我选择了C++,这个领域我没有其他选择,当我开始网络游戏服务器/客户端开发的时候,我需要一种高效的嵌入式脚本语言(工作需要)我选择了LUA这样的小众语言,再后来,我感觉自己希望加深对Linux/Unix的理解,并且习惯在Shell下工作时,我学习了bash(不知道是用的太少,还是没有理解其精髓,总感觉语法过于扭曲,实际上用bash的时候更喜欢用其兼容csh的”(())”语法,特别是当我不当使用,用其实现算法的时候-_-!),再再后来,我希望有一种足够好,足够通用,并且和C/C++能够很好交互的脚本语言时,我选择了Python,它也一直在给我惊喜:)虽然它的速度实在不咋的,但是,当我开始使用Python的时候,速度明显不是我关心的东西了,别忘了。。。作为程序员,我的母语是C++。理解你需要的,做出适当的选择,可能这才是王道。。。。。
write by 九天雁翎(JTianLing) -- www.jtianling.com
阅读全文....
其实C++比Python更需要lambda语法,可惜没有。。。。
write by 九天雁翎(JTianLing) -- www.jtianling.com
讨论新闻组及文件
思路有点混乱,想到哪就写到哪了。
起点是Python,Python的语法大都简单,有人说接近自然语言,但是其实我还是发现了一些不那么通俗易懂的东西,也许是因为还没有形成深刻的Python思维,也许是受C++的熏陶太深吧,其中,Python的函数式编程方式上就有很多地方感觉语法比较不那么容易一眼就看出来。其实想到函数式编程,倒是首先想到了lambda,自此思路混乱。对于将函数作为第一类(first class)值的语言,比如Python,lua中,感觉lambda的作用就不是那么明显,比如Python中,调用lambda的实际需求似乎感觉不算太大,再加上其函数定义的语法本身就足够的简洁,定义一个完整的函数实在也不算什么。作为语法糖的lambda,实在就显得有点甜味不足,虽然也不是说完全没有用。
这里举几个例子:
def add1(a,b): return a + b
add2 = lambda a,b : a + b
print add1(1,2)
print add2(1,2)
fun = lambda f,a,b : f(a,b)
print fun(lambda a,b : a * b, 3, 4)
print fun(add1, 3, 4)
可以看出,对于lambda这样的语句,假如在Python中还有作用的话,那么就是在需要函数作为参数传递的时候了,但是个人还是保持这样的观点,因为python这样的动态类型语言+足够简洁的函数定义语法+函数第一类型值的特点导致实际上lambda不够甜,虽然其可以进一步的简化一些语法。
但是,假如C++中有lambda那就是完全不同的概念了,看看同样的事情吧:
int add(int a, int b)
{
return a + b;
}
template<typename T>
T add1(T lhs, T rhs)
{
return lhs + rhs;
}
template<typename T>
class add2
{
public:
T operator()(T lhs, T rhs)
{
return lhs + rhs;
}
};
template<typename FUN, typename T>
T fun(FUN function, T lhs, T rhs)
{
return function(lhs, rhs);
}
int main()
{
int a = 1;
int b = 2;
cout << add1(a,b) <<endl;
cout << fun( ptr_fun(add), 1, 2) <<endl;
cout << fun( add, 1, 2) <<endl;
cout << fun( add1<int>, 1, 2) <<endl;
cout << fun( ptr_fun(add1<int>), 1, 2) <<endl;
cout << fun(add2<int>(), 1, 2) <<endl;
system("PAUSE");
}
可以看到,相对而言C++的函数定义语法,包括使用方式上都会比Python要复杂一些,最主要的复杂性来之于C++赖以生存的根本,强类型,为了达到类型安全又类型无关,引入的模板机制,进一步的复杂化了函数的定义。
最有意思的是,
cout << fun( add1<int>, 1, 2) <<endl;
cout << fun( ptr_fun(add1<int>), 1, 2) <<endl;
这两种方式,在开启/clr,即开启微软的公共运行时库时会出现异常,我还是在反汇编时发现汇编代码异常才发现原来我在上次调试for_each的时候,为了展示/clr的新添的for each语法而开启了/clr选项,详情可以见《多想追求简洁的极致,但是无奈的学习C++中for_each的应用》一文。
/clr选项应该就是将C++加入微软的.net体系,因为没有深入学习过,所以对出现的异常现象无法解释,希望有学过.net的人可以解释一下。
另外,这里想说的是,因为C++没有原生的for each语法,所以实际上很多循环不想写的话只能通过for_each算法来模拟,再加上很大一族的算法函数对于函数对象的需求,导致了语法的极大复杂化,使得C++对于lambda语法的需求远远大于Python这样的语言,但是,遗憾的是,C++并没有这样的语法,实际上09标准中好像有人提议过这样的特性,不过不知道通过没有-_-!就我目前所知,否决的可能性要大得多,但是因为没有仔细去查阅资料了,所以不敢肯定,但是很明显TR1中是没的,新出来的g++中新添了很多09标准要出来的特性中也没有包含lambda,似乎我们可能在短时间内(起码下一版标准。。。又要起码十年)是没有机会了。
《多想追求简洁的极致,但是无奈的学习C++中for_each的应用》一文,为了能够简单的让c++模拟出for each语法的调用,我甚至都不得不将很多循环进行两次。。。。。。详细情况见前文,就知道假如能有lambda,那么我们就能够省下多少函数的定义了。这里我就不在重复原文中的例子了。
事实上,还是如同boost::foreach库一样,虽然没有这样的语法,但是C++界的牛人们绝不允许这样的情况发生,他们想要什么,就会有什么,如同当年上帝。。。。要有光,于是就这么有了。。。。。看看boost的lambda库能给我们带来什么。
#include <list>
#include <iostream>
#include <boost/foreach.hpp>
#include <boost/lambda/lambda.hpp>
using namespace std;
using namespace boost::lambda;
template<typename T>
void printInt(T i)
{
cout <<i <<endl;
}
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
for(list<int>::const_iterator lit = l.begin(); lit != l.end(); ++lit)
{
cout <<*lit <<endl;
}
// 同样是需要输出
for_each(l.begin(), l.end(), ptr_fun(printInt<int>));
BOOST_FOREACH( int i, l)
{
cout <<i <<endl;
}
// 因为Andrew koenig发明的操纵器的特性,boost::lambda无法支持
for_each(l.begin(), l.end(), cout <<_1 <<'/n');
system("PAUSE");
}
一条语句,省下了很多工作,只当有这样简洁的实现方式时,我们才能够大规模的利用for_each去代替无聊的循环,非常高频率出现的循环,并且,虽然说Boost实现的lambda语法和一般而言有点区别,但是还算是比较容易理解,在没有for each语法前,我最希望有的可能就是lambda语法了,我希望利用算法来代替循环,但是没有lambda前,那样做可能比不费脑子的写个循环更加费力不讨好,甚至流于语言特性的滥用。还是在《多想追求简洁的极致,但是无奈的学习C++中for_each的应用》一文中,后面的例子就可以看出在没有这些语法特性时,我希望实现一个那么简单的功能所付出的代价。
这里为了方便,还是拷贝一次原文中的例子:
Python中:
def add(a,b):
return a + b
l = [1,2,3,4,5]
for i in l:
print add(i,1)
无非就是在每个输出的函数中调用一个函数,没有任何值的一提的地方,是个人就能看懂。
在C++需要实现成下面这个样子:
#include <list>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
template <typename T>
class Add : public binary_function<T, T, void>
{
public:
void operator()(const T& ai, const T& aj) const
{
cout <<(ai + aj) <<endl;
}
};
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
for_each(l.begin(), l.end(), bind2nd(Add<int>(), 1));
system("PAUSE");
}
这是在没有lambda和for each语法时无奈的实现。
假如有lambda语法的话,那么感觉就不同了。
#include <list>
#include <iostream>
#include <boost/foreach.hpp>
#include <boost/lambda/lambda.hpp>
using namespace std;
using namespace boost::lambda;
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
for(list<int>::const_iterator lit = l.begin(); lit != l.end(); ++lit)
{
cout <<*lit + 1 <<endl;
}
for_each(l.begin(), l.end(), cout <<_1+1 <<'/n');
system("PAUSE");
}
还是几乎与原有的不+1输出实现同样的简洁,这就是lambda带来的特性,在没有这些特性的时候,我们就只能老老实实的按iterator的方式写了,在C++苦海中挣扎的兄弟们啊。。。。(特别是像我这样,工作中甚至连boost都不能用的人啊。。。。)继续等待吧。。。。等09标准出来。。。等VS202X版本的VS出来后,估计差不多才可能实现新的C++ 09标准,然后我们也许能够稍微减轻点工作量,以后能够写成大概是
for(auto lit = l.begin(); lit != l.end(); ++lit)
{
cout <<*lit + 1 <<endl;
}
这个样子。。。。。。。。。。。。。。阿门。
write by 九天雁翎(JTianLing) -- www.jtianling.com
阅读全文....
程序员手中的利器(1)--工欲善其事必先利其器
write by 九天雁翎(JTianLing) -- www.jtianling.com
不要和讲述工具不是最重要的理论,我知道,并且就是一直被其所害。这里我得说明一下,在最开始学习某种编程语言的时候的确应该主要关注与语言特性的学习而不是被一些复杂的IDE所分心,但是当真的成为一个程序员后,当渐渐的一种语言对你来说也就是一种工具的时候,那些IDE一样的工具,也应该值得你花同样的实现去学习!
这里主要也就是列出平时我用到的工具,自从刚开始工作的时候被总监一句“工欲善其事必先利其器”的话警醒,从以前学习时那种语言才是最重要的,IDE什么都仅仅是个工具而已的思想中走出来。我开始有意识的花功夫去学习那些以前我很不屑去学习的工具。事实上,作为一个计算机面前工作的人员(其实不仅仅是程序员),熟悉好你手中的每一个工具,那都是节省你时间的法宝,同时,节省的是你的生命。(虽然说主要是提高你的工作效率。)并且,因为好的工具可能最主要关注的是熟练使用者的使用效率,所以往往都不那么“初学者友好”,使很多人望而却步,但是在我逐渐的去熟悉了这样一些工具以后,我总是会发现,我用来学习一个好工具的时间,到头来总是会远远的少于用一个好工具为我节省的时候,所以,一个好工具几乎总是值得投入足够的精力去学习的,毕竟,学会了一个好工具会一直受用!这点,我深有体会!
作为一个列表,得有个分类和顺序,先列表,然后再讲理由吧。
文本编辑工具:特别推荐vim! Windows/Linux/X多平台通用
辅助:Ultra Edit:Windows下偶尔用用
IDE: Visual Studio 2005(VS2005) Windows下的C++开发环境
Eclipse: Windows/X 多种语言跨平台综合开发环境
代码控制:Visual Source Safe(VSS):Windos下与VS2005结合使用
SVN,CVS:Linux下及开源需要
调试:gdb: linux/X 需要
pydb: Linux Python语句调试
bashdb: Linux bash 语言调试
工程控制:GNU make:Linux
编译器: gcc:Linux
UML: IBM Rational rose:windows,最强大的UML工具,毋庸置疑
测试工具:Compuware DevPartner: windows下用于检测代码错误或者内存泄露
备选工具:Visual Studio Team版自带C++代码分析工具
Profiler: AQTime:Windows下代码运行时间分析工具
8. 资源管理器:Total Command:Windows
9. 比较工具:Beyond compare:Windows
10. 16进制编辑工具:WinHex, 我认为Windows下最佳的16进制编辑工具
HView:Windows,同样优秀,除了界面有点老,支持对PE文件格式的分析及内带反汇编功能
11. 反汇编静态分析:IDA Pro,Windows/Linux,基本上,有这一个就够了,w32dm什么的我好像没有需要过。
12. 反汇编动态调试工具:OllyDbg, Windows 的确比较容易上手,功能也很强大
SoftIce,Windows ring0调试工具
13. SSH客户端: WinSCP,图形界面,主要用于远程登陆Linux服务器做文件管理用
Putty 个人感觉不错的远程控制台
以上Linux都是特指Linux下的控制台,X才是指Linux下的图形界面环境
从此列表中可以看出,我的主要工作环境还是Windows,这是工作需要,但是由于工作中服务器需要跑在Linux下加上个人爱好,所以也掌握了一些Linux下的工具,但是由于我主要是通过Putty登陆Linux服务器工作,所以对于X下的工具了解不多。再加上个人爱好和前段时间反外挂的工作,所以还了解了一些反汇编工具的使用。
再说一次的是,这个列表仅仅是我个人平时使用的软件列表,并不代表人人都喜欢,或者世界最高水平。。。。。。-_-!
以下为逐条分析,因为精力有限,可能主要讲一些我个人的看法,至于大家都知道的东西讲太多也没有意义,并且以精简为主,不然的话光是讲vim好用的插件都可以用一天的时间来写。另外。。。本来准备写一篇小文章来总结一下自己所用工具的,但是发现这个话题一旦开始,就很难收尾了。。。。结果。。。又是一个系列。
BTW:万恶的ASP.net,明显和FireFox不兼容,我在FF中发表的文章在IE中都看不到,虽然可以参考原则,IE不能看的空文章用FF浏览。。。但是,这些文字也看不到吧。。。还是重发一下吧
write by 九天雁翎(JTianLing) -- www.jtianling.com
阅读全文....
这不是写给初学编程的人看的书,他们还是好好的听好亘古不变的教诲,“努力学习语言本身,不要被工具所干扰”;这不是写给一般的程序员看的书,他们迷失在各种各样的新兴语言之中;这也不是给一个对编程这种工作没有热情的人看的,因为工作效率再高,对他们来说,也仅仅是被剥削的更加严重。但是,假如你是和我一样,热爱着编程,即便是被剥削至最后一滴血也绝不罢休的提高着自己的工作效率,能够用键盘完成的绝不用鼠标完成,能够点一次鼠标完成就绝不点第二次,能够敲一个键完成的绝不敲第二个键,能够自动化完成的绝不手动完成的程序员的话,这会是你想要看的书,也会是你喜欢看的书,你会发现,原来你还有志同道合者,原来还有人和你一样,懂得怎么艺术性的操作电脑,懂得怎么让电脑干它该干的事情,而不是让自己去干那些重复性的工作,哪怕老板交代的任务多么枯燥和具有重复性,也能有技术的艺术性的完成,而且,比一般人完成还要快一个数量级。
阅读全文....
多想追求简洁的极致,但是无奈的学习C++中for_each的应用
write by 九天雁翎(JTianLing) -- www.jtianling.com
讨论新闻组及文件
for each语法是方便的,也是很自然的,这也是为什么很多语言都有这样的语法,就我所知,包括java(jdk5.0以上),python,php,asp.net等语言都有类似的语法,甚至微软为C++/CLI中也添加了这样的语法。但是很遗憾的是,C++98标准中没有,于是,我们只能通过可悲的for_each算法去模拟。。。。。。。。。。先看看原生的语法是多么方便和自然的吧,虽然有人将其视为语法糖,但是,就算是糖,这也是很甜的那种。
先看看Python中的循环,虽然不是for each,但是类似于。
l = [1,2,3,4,5]
for i in l:
print i
简洁,干净,
假如你有幸使用微软的托管C++,你可以使用类似的语法:
using namespace System;
#include <list>
#include <iostream>
using namespace std;
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
for each ( int i in l)
Console::Write(i);
system("PAUSE");
}
虽然作为强类型语言,在声明方面稍微复杂点,循环的处理还是那么简洁,干净。
再来看看现有的C++中的:
#include <list>
#include <iostream>
using namespace std;
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
// 同样是需要输出
for(list<int>::const_iterator lit = l.begin(); lit != l.end(); ++lit)
{
cout <<*lit <<endl;
}
system("PAUSE");
}
繁复到我都不想说了,list<int>::const_iterator似的迭代器声明语法不符合一处定义的原则,冗余信息太多。(C++09添加的auto用法就是解决此问题的),即便是解决了此问题,还是会发现,在C++中写个循环比在python(仅仅是一个例子,其他有类似for each特性的语言都比C++简单)中复杂太多了。而循环实在是太过于常见的语法了,所以一次又一次使用这种本可以简单,但是受限于语法而搞得这么复杂的C++可怜语法的时候,我总是忍不住想要吐血。对于这么简单的例子,我们是可以找到一些方法来稍微简化一点的。没有for each语法,我们起码还有for_each算法-_-!
于是可以这样:
#include <list>
#include <iostream>
#include <algorithm>
using namespace std;
void printInt(int i)
{
cout <<i <<endl;
}
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
// 同样是需要输出
for_each(l.begin(), l.end(), ptr_fun(printInt));
system("PAUSE");
}
在加大了理解难度后(本来for each语法多简单啊,现在还要理解ptr_fun这样的函数对象生成的辅助函数),我们的循环是稍微简单一点了,虽然在这个例子中我们甚至要额外写函数-_-!虽然说函数可以只写一次,循环可是常常用的啊。
对于这样简单的例子,已经可以看出没有for_each语法的痛苦了,再复杂一点的例子
对于类成员函数的调用,看看有for_each的情况
python中:
class Add():
def __init__(self, i):
self._i = i
def add(self):
self._i += 1
def __str__(self):
return str(self._i)
s = [Add(1), Add(2), Add(3)]
for a in s:
a.add()
for a in s:
print a
这里拆分成两个函数,可以看出我的无奈,想要在一个for_each语法中连续调用两个函数的方法。。。。目前只有再写一个函数,而这个函数的作用就是仅仅调用这两个函数提供给for_each使用。不说这些丧气+无奈的话了,光是调用一个类的成员函数的可能还是有的。
C++中:
#include <list>
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
void printInt(int i)
{
cout <<i <<endl;
}
class CAdd
{
public:
CAdd(int ai):mi(ai) { }
void add() { ++mi; }
operator int() { return mi;}
int mi;
};
int main()
{
CAdd a[3] = { CAdd(1), CAdd(2), CAdd(3)};
list<CAdd> l(a, a+3);
// 同样是需要输出
for_each(l.begin(), l.end(), mem_fun_ref(&CAdd::add));
for_each(l.begin(), l.end(), ptr_fun(printInt));
system("PAUSE");
}
为了实现循环的简洁,重新引入了新的复杂度,mem_fun_ref,希望一般的C++程序员见过这样的函数对象辅助函数。。。。还多了类似&CAdd::add这样的成员函数指针的语法,希望一般的程序员也能理解。。。。(不提有for each语法的语言中除了for each这样自然的语法外,做多复杂的运算都没有引入任何新的复杂度),最主要的是,你想要在一条for_each中实现两个函数的调用,你除了老老实实的实现一个新的函数外,就是像我这样了,调用for_each两次,两种方法都是不那么容易让人接受。。。。。。。。但是,在现有的C++中,我们也就只能做到这样了。既然用C++,就接受现实吧。其实,显示远比一般人想象的要复杂。
以上情况还是函数没有参数的时候,当函数有参数的时候,新的问题又来了。
看看python中这样一个简单的功能:
def add(a,b):
return a + b
l = [1,2,3,4,5]
for i in l:
print add(i,1)
无非就是在每个输出的函数中调用一个函数,没有任何值的一提的地方,是个人就能看懂。
在C++需要实现成下面这个样子:
#include <list>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
template <typename T>
class Add : public binary_function<T, T, void>
{
public:
void operator()(const T& ai, const T& aj) const
{
cout <<(ai + aj) <<endl;
}
};
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
for_each(l.begin(), l.end(), bind2nd(Add<int>(), 1));
system("PAUSE");
}
到这一步,我希望大部分的C++程序员还能看懂什么意思及其实现的机制。。。。但是仅仅是我的希望吧,甚至我怀疑,这样的实现放在工作中,总监和老总是不是会将我批的体无完肤,的确,为了省略一个循环值得这样做吗?实在不值得,但是C++提供给你的机制就是这样。Add这样的函数对象构造复杂,还得利用trail机制(从binary_function类继承过来),然后再利用函数适配器bind2nd/bind1st,这样的东西似乎需要语言专家来解释,我是解释不清楚了,再加上更加复杂的函数连标准库中的bind都肯定不够用,还只能用boost::bind库,去试试吧,然后会发现一般的函数指来指去(特别是类成员)用的太复杂了,还是用boost::funciton吧。。。。。似乎永无止境。但是有了for each语法,那么什么复杂度都没有。。。。。还想自虐吗?算了吧,我基本上已经放弃了。不给糖吃,也放不着自己开工厂制作。。。。
另外,对于能够用boost的兄弟们,糖是有的吃的。boost:: foreach库即是如此。
下面是boost:: foreach的例子
#include <list>
#include <iostream>
#include <boost/foreach.hpp>
using namespace std;
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
BOOST_FOREACH( int i, l)
{
cout <<i <<endl;
}
BOOST_FOREACH( int i, l)
{
cout <<i+1 <<endl;
}
system("PAUSE");
}
就算仅仅这一个例子。。。。永远不要怪库开发者(比如boost,ace,loki)将C++语言弄得多么扭曲,他们也是出于无奈。。。。别去看实现,先只管用吧。
对于不能用boost的我。。。。只能看有没有办法偷偷的将/cli编译选项打开了。。。^^
write by 九天雁翎(JTianLing) -- www.jtianling.com
阅读全文....
Observer模式的升级版,Event通知实现
write by 九天雁翎(JTianLing) -- www.jtianling.com
讨论新闻组及文件
本来这段程序是为mmgwg小组程序做示范写的,但是想想最近也很少有时间在家这样写程序了。。。。还是放上来吧,应该对有类似需求的兄弟们也有一些示范作用,对于程序的类层次结构就没有更多的深究了,仅仅是表达大概的意思,并不是希望大家都像我一样所有的实现都跑到父类中去。切记。
要说明的是,原始的Observer模式仅仅说明了一种思想,但是使用价值并不高,因为很简单的道理,作为一个系统基础的行为模式,其仅仅支持一种通知方式,并且是遍历通过。。。(这也可以看做模式的说明仅仅是实现了一种很通用的情况,并不是最好的实现),我们使用的也可以看作是Observer模式的延伸,也可以看做Observer模式的另一种实现,是所谓的 Event通知方式。在实际代码中使用非常多。在我们公司代码中似乎不论是服务器还是客户端代码都需要用到。服务器代码中甚至为了实现策划编辑数据另外做了一套(也就是并行的两套)。
具体的例子我打包放到
http://groups.google.com/group/jiutianfile/
中了,文件名为Event Drive sample code.rar
程序没有经过调试,仅仅是编译通过,请仅仅作为示范使用。其中唯一比较难掌握的可能就是类成员函数的指针了,但是难的主要是语法,真正的使用上没有太多问题。
Observer.h
#ifndef __OBSERVER_H__
#define __OBSERVER_H__
#include "BaseDefines.h"
class CSubject;
class CObserver
{
typedef LRESULT (CObserver:: *EventFunc)(LPARAM , WPARAM , WPARAMEX );
public:
CObserver(CSubject* apSubject);
virtual ~CObserver(void);
bool InitEvent();
// 此接口相当于原设计模式中的Update
LRESULT OnEvent(EventID_t aiEventID, LPARAM aLParam, WPARAM aWParam, WPARAMEX aWParamEx);
typedef map<EventID_t, EventFunc> EventMap_t;
typedef EventMap_t::iterator EventIter_t;
EventMap_t moEvents;
// 以下仅为示例,即是各个事件的相应
LRESULT OnEvent1( LPARAM aLParam, WPARAM aWParam, WPARAMEX aWParamEx);
LRESULT OnEvent2( LPARAM aLParam, WPARAM aWParam, WPARAMEX aWParamEx);
LRESULT OnEvent3( LPARAM aLParam, WPARAM aWParam, WPARAMEX aWParamEx);
CSubject *mpSubject;
};
#endif
Observer.cpp
#include "StdAfx.h"
#include "Observer.h"
#include "Subject.h"
CObserver::CObserver(CSubject* apSubject):mpSubject(apSubject)
{
InitEvent();
}
CObserver::~CObserver(void)
{
}
// 此实现中通过aiEventID分发事件,具体方式类似于MFC的消息映射
LRESULT CObserver::OnEvent( EventID_t aiEventID, LPARAM aLParam, WPARAM aWParam, WPARAMEX aWParamEx )
{
EventIter_t lit = moEvents.find(aiEventID);
if(lit == moEvents.end())
{
// 表示Observer实际没有订阅此事件。
return -1;
}
// 假如有订阅,则调用相应的响应函数
return ( this->*(lit->second))(aLParam, aWParam, aWParamEx);
}
bool CObserver::InitEvent()
{
moEvents.insert(make_pair(1, &CObserver::OnEvent1));
moEvents.insert(make_pair(2, &CObserver::OnEvent2));
moEvents.insert(make_pair(3, &CObserver::OnEvent3));
return true;
}
LRESULT CObserver::OnEvent1( LPARAM aLParam, WPARAM aWParam, WPARAMEX aWParamEx )
{
return 1;
}
LRESULT CObserver::OnEvent2( LPARAM aLParam, WPARAM aWParam, WPARAMEX aWParamEx )
{
return 1;
}
LRESULT CObserver::OnEvent3( LPARAM aLParam, WPARAM aWParam, WPARAMEX aWParamEx )
{
return 1;
}
Subject.h
#ifndef __SUBJECT_H__
#define __SUBJECT_H__
#include "BaseDefines.h"
#include <map>
#include <list>
using namespace std;
class CObserver;
class CSubject
{
public:
CSubject(void);
virtual ~CSubject(void);
bool Attach( EventID_t aiEventID, CObserver *apObs);
bool Detach( EventID_t aiEventID, CObserver *apObs);
// 类似原Observer模式中的Notice消息
LRESULT SendEvent(EventID_t aiEventID, LPARAM aLParam, WPARAM aWParam, WPARAMEX aWParamEx );
typedef list<CObserver*> ObsList_t;
typedef ObsList_t::iterator ObsIter_t;
typedef map<EventID_t, ObsList_t> EventObsMap_t;
typedef EventObsMap_t::iterator EventObsIter_t;
EventObsMap_t moEventObsMap;
};
#endif
Subject.cpp
#include "StdAfx.h"
#include "Subject.h"
#include "Observer.h"
#include <boost/bind.hpp>
CSubject::CSubject(void)
{
}
CSubject::~CSubject(void)
{
}
bool CSubject::Attach( EventID_t aiEventID, CObserver *apObs )
{
EventObsIter_t lit = moEventObsMap.find(aiEventID);
if(lit != moEventObsMap.end())
{// 已经有相关的事件响应Obs列表
ObsList_t& lObsList = lit->second;
ObsIter_t litList = find(lObsList.begin(), lObsList.end(), apObs);
if(litList != lObsList.end())
{// 重复Attach
return false;
}
lObsList.push_back(apObs);
return true;
}
// 实际上先添加list到map然后再添加bos效率会略高。
ObsList_t lObsList;
lObsList.push_back(apObs);
// 此insert必成功
#ifdef _DEBUG
pair<EventObsIter_t, bool> lpairResult = moEventObsMap.insert(make_pair(aiEventID, lObsList));
ASSERT(lpairResult.second);
#else
moEventObsMap.insert(make_pair(aiEventID, lObsList));
#endif
return true;
}
bool CSubject::Detach( EventID_t aiEventID, CObserver* apObs )
{
EventObsIter_t lit = moEventObsMap.find(aiEventID);
if(lit == moEventObsMap.end())
{// 根本没有订阅此消息
return false;
}
ObsList_t& lObsList = lit->second;
ObsIter_t litList = find(lObsList.begin(), lObsList.end(), apObs);
if(litList == lObsList.end())
{// 根本没有订阅此消息
return false;
}
// 这里当list为空的时候也不删除map中的对应item,添加的时候速度更快,也没有删除的时间,消耗多一点内存,但是减少内存碎片
lObsList.erase(litList);
return true;
}
LRESULT CSubject::SendEvent( EventID_t aiEventID, LPARAM aLParam, WPARAM aWParam, WPARAMEX aWParamEx )
{
EventObsIter_t lit = moEventObsMap.find(aiEventID);
if(lit == moEventObsMap.end())
{// 根本没有Observer订阅此消息
return 0;
}
ObsList_t& lObsList = lit->second;
for(ObsIter_t litList = lObsList.begin(); litList != lObsList.end(); ++litList)
{
(*litList)->OnEvent(aiEventID, aLParam, aWParam, aWParamEx);
}
return 1;
}
write by 九天雁翎(JTianLing) -- www.jtianling.com
阅读全文....