C++杂谈
C++是我最喜欢的语言,它集自由、博大、复杂、简约、高效于一身,又能很好地均衡这些特点,使它们和平共处,将“不为用到的任何特性付出一点点代价”的宗旨贯彻到底,其他的任何一种语言的都不具备像C++这样的内涵,使用C++之时,直有C++在手,江山我有的感觉。C虽然能让你掌管一切,但用C开发,有如戴着镣铐在跳舞,无时不刻要小心翼翼地人肉管理一切细节,实在太累了。而用C#、JAVA等其他语言时,虽然养尊处优,但想走不寻常路之时,又处处受限制,很有点寄人篱下的味道,未免不痛快。只有C++,既能下,又能上,进可攻,退可守,想怎么样就怎么样,尽情地飞翔。只要你愿意,你就可以在这一片世界里随心所欲地发挥你的一切聪明才智,创造出种种奇技淫巧,而不会受到一点点约束。问题来了,自由得过头了,就失去了控制,自由未必是好事。好多人,自由得甚至忘记了他要用C++的根本目的是什么,于是,C++到了他的手里,就变成为自由而自由,为复杂而复杂的利器,不但用它来折磨自己,还用它来迷惑别人,以致于忽视了原本要解决的问题,这样一来,问题就很严重了。好的工具本来就是要用来做点实事的,做不了实事,要拿什么来证明自己呢?
对于C++,没什么好说的。但C++的教育,就有太多的不满,要指责之处,也实在太多了,其中最为人诟病,就是很多C++的教材,都鼓励读者将注意力集中到C++的细节中,而忘记了如何用C++来简洁质朴地来表达设计思路。关于这一点,很多达人君子也已经一再严厉地批评再批评。我也不想重复他们的论调,只想举两个例子。
C++因缺乏GC,而广受非议。但内存管理,其实不值得议论再议论,只要设计编写得当,少耍小聪明,代码中出现new和delete的次数可以很少很少,就算出现,也只会出现于底层代码中。为了弥补GC的缺席,C++界中发明了种种内存管理的巧妙手法,其中最得力的一种办法就是智能指针,而出现于标准库中就是大名鼎鼎的auto_ptr了,甚至有人说,一本C++的教材,只要不介绍auto_ptr,就不属于合格的教科书。但其实,auto_ptr并不见得那么重要,好比以下的代码
Int* pa = new int;
……
delete pa;
这代码确实不好,于是该auto_ptr上场表演,变成
auto_ptr<int*> pa(new int);
delete消失了,何其美妙,但其实,最朴实的代码,连new都可以不用的,既然没有new,就不需要auto_ptr了,最简洁的代码,非常简单。
Int a = 0;
一行就好,什么都用不了,很多出现auto_ptr的地方,直接用局部变量就可以了。不能使用局部变量的地方,就属复杂的内存管理了,在那里分配,在那里释放,都很有必要细细地斟酌一番,auto_ptr并非什么万能丹,一有内存分配,就搬出auto_ptr,只怕属本本主义的作风。即此以观,什么share_ptr,scope_ptr,也就那么一点点作用而已,无须大书特书。
我承认,BOOST精妙无比,那都是C++程序聪明才智的结晶,但其实,真正搬得上台面,发挥大作用的玩意,为数并不多,好比Tuple,可以方便地返回函数中的多个结果,例如……(请大家自己动手,或baidu或google),乍听起来,似乎美妙无比。但其实,没什么作用,什么时候,我们需要从函数中返回多个值?需要从函数中返回多值时,我会尽量地写本地代码,实在必须调用函数了,只好搬出指针或引用,将参数传递进去,如果数量太多了,那就动用结构,用结构组织这些返回值,这一切,做起来,并没什么太大的不便。但是如果动用Tuple返回多个结果,可能方便了那么一点点,却将导致代码难以维护,因为Tuple里面的值各表示了什么意思,无法直接从代码中看得出来,用过Tuple的同学自然知道我要说什么。Tuple的实现非常巧妙,如此费尽心思弄出来的东西,不过是一只漂亮花瓶而已,真让人扼腕叹息不已,很多C++的库,尤其是BOOST,都是这个样子,看起来很精致,用起来,却完全不是那么一回事,而且还引入很多不必要复杂性,世人称心智包袱。
……
用C++做设计,很容易就导致库设计,如果设计出来的库有用好用,那也罢了,问题是费了九牛二虎之力,搞出来的东西,半点得不到别人的认可,甚至连自己都无法认可,那就太不应该了。
用C++写代码,老老实实地写代码,不要忘记了编程的用意,别沉浸于语言中,尽量将代码写得直白易懂,少卖弄聪明才智, 慎用C++的一切特性,继承、虚函数、操作符重载、模板、异常、new delete、……,更加不要用它们创造出什么奇技淫巧,必须用它们的时候,必须要有使用它们的理由。确实存在必须使用它们的理由,还坚决不用,那就是傻瓜和偏执狂了,这不是合格的C++码农,C++虽然不喜欢胡作非为的捣蛋鬼,但也杜绝一切墨守成规的书呆子。