C++的坑真的多吗?

C++的坑真的多吗?

先说明一下,我不希望本文变成语言争论贴。希望下面的文章能让我们客观理性地了解C++这个语言。(另,我觉得技术争论不要停留在非黑即白的二元价值观上,这样争论无非就是比谁的嗓门大,比哪一方的观点强,毫无价值。我们应该多看看技术是怎么演进的,怎么取舍的。)

事由

周五的时候,我在我的微博上发了一个贴说了一下一个网友给我发来的C++程序的规范和内存管理写的不是很好(后来我删除了,因为当事人要求),我并非批判,只是想说明其实程序员是需要一些“疫苗”的,并以此想开一个“程序员疫苗的网站”,结果,@简悦云风同学直接回复到:“不要用 C++ 直接用 C , 就没那么多坑了。”就把这个事带入了语言之争。

我又发了一条微博

@左耳朵耗子 新浪个人认证 : 说C++比C的坑更多的人我可以理解,但理性地思考一下。C语言的坑也不少啊,如果说C语言有90个坑,那么C++就是100个坑(另,我看很多人都把C语言上的坑也归到了C++上来),但是C++你得到的东西更多,封装,多态,继承扩展,泛型编程,智能指针,……,你得到了500%东西,但却只多了10%的坑,多值啊

结果引来了更多的回复(只节选了一些言论):

  • @淘宝褚霸也在微博里说:“自从5年前果断扔掉C++,改用了ansi c后,我的生活质量大大提升,没有各种坑坑我。
  • @Laruence在其微博里说: “我确实用不到, C语言灵活运用struct, 可以很好的满足这些需求.//@左耳朵耗子: 封装,继承,多态,模板,智能指针,这也用不到?这也学院派?//@Laruence: 问题是, 这些东西我都用不到… C语言是工程师搞的, C++是学院派搞的

那么,C++的坑真的多么?我还请大家理性地思考一下

C++真的比C差吗?

我们先来看一个图——《各种程序员的嘴脏的对比》,从这个图上看,C程序员比C++的程序员在注释中使用fuck的字眼多一倍。这说明了什么?我个人觉得这说明C程序员没有C++程序员淡定

Google Code 中程序语言出现 fuck 一词的比率

不要太纠结上图,只是轻松一下,我没那么无聊,让我们来看点真正的论据。

相信用过C++的程序员知道,C++的很多特性主要就是解决C语言中的各种不完美和缺陷:(注:C89、C99中许多的改进正是从C++中所引进的

  • 用namespace解决了很C函数重名的问题。
  • 用const/inline/template代替了宏,解决了C语言中宏的各种坑。
  • 用const的类型解决了很多C语言中变量值莫名改变的问题。
  • 用引用代替指针,解决了C语言中指针的各种坑。这个在Java里得到彻底地体现。
  • 用强类型检查和四种转型,解决了C语言中乱转型的各种坑。
  • 用封装(构造,析构,拷贝构造,赋值重载)解决了C语言中各种复制一个结构体(struct)或是一个数据结构(link, hashtable, list, array等)中浅拷贝的内存问题的各种坑。
  • 用封装让你可以在成员变量加入getter/setter,而不会像C一样只有文件级的封装。
  • 用函数重载、函数默认参数,解决了C中扩展一个函数搞出来像func2()之类的ugly的东西。
  • 用继承多态和RTTI解决了C中乱转struct指针和使用函数指针的诸多让代码ugly的问题。
  • 用RAII,智能指针的方式,解决了C语言中因为出现需要释放资源的那些非常ugly的代码的问题。
  • 用OO和GP解决各种C语言中用函数指针,对指针乱转型,及一大砣if-else搞出来的ugly的泛型。
  • 用STL解决了C语言中算法和数据结构的N多种坑。
(注意:上面我没有提重载运算符和异常,前者写出来的代码并不易读和易维护(参看《恐怖的C++语言》后面的那个示例),坑也多,后者并不成熟(相对于Java的异常),但是我们需要知道try-catch这种方式比传统的不断地判断函数返回值和errno形成的大量的if-else在代码可读性上要好很多)

上述的这些东西填了不知有多少的C语言编程和维护的坑。少用指针,多用引用,试试autoptr,用用封装,继承,多态和函数重载…… 你面对的坑只会比C少,不会多。

C++的坑有多少?

C++的坑真的不多,如果你能花两到三周的时候读一下《Effecitve C++》里的那50多个条款,你就知道C++里的坑并不多,而且,有很多条款告诉我们C++是怎么解决C的坑的。然后,你可以读读《Exceptional C++》和《More Exceptional C++》,你可以了解一下C++各种问题的解决方法和一些常见的经典错误。

当然,C++在解决了很多C语的坑的同时,也因为OO和泛型又引入了一些坑。消一些,加一些,我个人感觉上总体上只比C多10%左右吧。但是你有了开发速度更快,代码更易读,更易维护的500%的利益。

另外,不可否认的是,C++中的代码出了错误,有时候很难搞,而且似乎用C++的人会觉得C++更容易出错?我觉得主要是下面几个原因:

  • C和C++都没学好,大多数人用C++写C,所以,C的坑和C++的坑合并了。
  • C++太灵活了,想怎么搞就怎么搞,所以,各种不经意地滥用和乱搞。

另外,C++的编译对标准C++的实现各异,支持地也千差万别,所以会有一些比较奇怪的问题,但是如果你一般用用C++的封装,继承,多态,以及namespace,const, refernece,  inline, templete, overloap, autoptr,还有一些OO 模式,并不会出现奇怪的问题。

而对于STL中的各种坑,我觉得是程序员们还对GP(泛型编程)理解得还不够,STL是泛型编程的顶级实践!属于是大师级的作品,一般人很难理解。必需承认STL写出来的代码和编译错误的确相当复杂晦涩,太难懂了。这也是C++的一个诟病。

这和Linus说的一样 —— “C++是一门很恐怖的语言,而比它更恐怖的是很多不合格的程序员在使用着它”。注意我飘红了“很多不合格的程序员”!

我觉得C++并不适合初级程序员使用,C++只适合高级程序员使用(参看《21天学好C++》和《C++学习自信心曲线》),正如《Why C++》中说的,C++适合那些对开发维护效率和系统性能同时关注的高级程序员使用。

这就好像飞机一样,开飞机很难,开飞机要注意的东西太多太多,对驾驶员的要求很高,但你不能说飞机这个工具很烂,开飞机的坑太多。(注:我这里并不是说C++是飞机,C是汽车,C++和C的差距,比飞机到汽车的差距少太多太多,这里主要是类比,我们对待C++语言的心态!)

C++的初衷

理解C++设计的最佳读本是《C++演化和设计》,在这本书中Stroustrup说了些事:

1)Stroustrup对C是非常欣赏,实际上早期C++许多的工作是对于C的强化和净化,并把完全兼容C作为强制性要求。C89、C99中许多的改进正是从C++中所引进。可见,Stroustrup对C语言的贡献非常之大。今天不管你对C++怎么看,C++的确扩展和进化了C,对C造成了深远的影响

2)Stroustrup对于C的抱怨主要来源于两个方面——在C++兼容C的过程中遇到了不少设计实现上的麻烦;以及守旧的K&R C程序员对Stroustrup的批评。很多人说C++的恶梦就是要去兼容于C,这并不无道理(Java就干的比C++彻底得多,但这并不是Stroustrup考虑的,Stroustrup一边在使尽浑身解数来兼容C,另一方面在拼命地优化C。

3)Stroustrup在书中直接说,C++最大的竞争对手正是C,他的目的就是——C能做到的,C++也必须做到,而且要做的更好。大家觉得是不是做到了?有多少做到了,有多少还没有做到?

4)对于同时关注的运行效率和开发效率的程序员,Stroustrup多次强调C++的目标是——“在保证效率与C语言相当的情况下,加强程序的组织性;能保证同样功能的程序,C++更短小”,这正是浅封装的核心思想。而不是过渡设计的OO。(参看:面向对象是个骗局

5)这本书中举了很多例子来回应那些批评C++有运行性能问题的人。C++在其第二个版本中,引入了虚函数机制,这是C++效率最大的瓶颈了,但我个人认为虚函数就是多了一次加法运算,但让我们的代码能有更好的组织,极大增加了程序的阅读和降底了维护成本。(注:Lippman的《深入探索C++对象模型》也说明了C++不比C的程序在运行性能低。Bruce的《Think in C++》也说C++和C的性能相差只有5%)

6)这本书中还讲了一些C++的痛苦的取舍,印象最深的就是多重继承,提出,拿掉,再被提出,反复很多次,大家在得与失中不断地辩论和取舍。这个过程让我最大的收获是——a) 对于任何一种设计都有好有坏,都只能偏重一方,b) 完全否定式的批评是不好的心态,好的心态应该是建设性地批评

我对C++的感情

我先说说我学C++的经历。

我毕业时,是直接从C跳过C++学Java的,但是学Java的时候,不知道为什么Java要设计成这样,只好回头看C++,结果学C++的时候又有很多不懂,又只得回头看C最后发现,C -> C++ -> Java的过程,就是C++填C的坑,Java填C++的坑的过程

注,下面这些东西可以看到Java在填C/C++坑:

  • Java彻底废弃了指针(指针这个东西,绝对让这个社会有几百亿的损失),使用引用。
  • Java用GC解决了C++的各种内存问题的诟病,当然也带来了GC的问题,不过功大于过。
  • Java对异常的支持比C++更严格,让编程更方便了。
  • Java没有像C++那样的template/macro/函数对象/操作符重载,泛型太晦涩,用OO更容易一些。
  • Java改进了C++的构造、析构、拷贝构造、赋值。
  • Java对完全抛弃了C/C++这种面向过程的编程方式,并废弃了多重继承,更OO(如:用接口来代替多重继承)
  • Java比较彻底地解决了C/C++自称多年的跨平台技术。
  • Java的反射机制把这个语言提升了一个高度,在这个上面可以构建各种高级用法。
  • C/C++没有一些比较好的类库,比如UI,线程 ,I/O,字符串处理等。(C++0x补充了一些)
  • 等等……

当然时代还在前进,这个演变的过程还在C#和Go上体现着。不过我学习了C -> C++  -> Java这个填坑演进的过程,让我明白了很多东西:

  • 我明白了OO是怎么一回事,重要的是明白了OO的封装,继承,和多态是怎么实现的。(参看我以前写过的《C++虚函数表解析》和《C++对象内存布局》)
  • 我明白了STL的泛型编程和Java的各种花哨的技术是怎么一回事,以及那些很花哨的编程方法和技术。
  • 我明白了C,C++,Java的各中坑,这就好像玩火一样,我知道怎么玩火不会烧身了。

我从这个学习过程中得到的最大的收获不是语言本身,而是各式各样的编程技术和方法,和技术的演进的过程,这比语言本身更重要在这个角度上学习,你看到的不是一个又一个的坑,你看到的是——各式各样让你可以爬得更高的梯子

我对C++的感情有三个过程:先是喜欢地要死,然后是恨地要死,现在的又爱又恨,爱的是这个语言,恨的是很多不合格的人在滥用和凌辱它。

C++的未来

C++语言发展大概可以分为三个阶段(摘自Wikipedia):

  • 第一阶段从80年代到1995年。这一阶段C++语言基本上是传统类型上的面向对象语言,并且凭借著接近C语言的效率,在工业界使用的开发语言中占据了相当大份额;
  • 第二阶段从1995年到2000年,这一阶段由于标准模板库(STL)和后来的Boost等程式库的出现,泛型程式设计在C++中占据了越来越多的比重性。当然,同时由于Java、C#等语言的出现和硬件价格的大规模下降,C++受到了一定的冲击;
  • 第三阶段从2000年至今,由于以Loki、MPL等程式库为代表的产生式编程和模板元编程的出现,C++出现了发展历史上又一个新的高峰,这些新技术的出现以及和原有技术的融合,使C++已经成为当今主流程式设计语言中最复杂的一员。

在《Why C++? 王者归来》中说了 ,性能主要就是要省电,省电就是省钱,在数据中心还不明显,在手机上就更明显了,这就是为什么Android 支持C++的原因。所以,在NB的电池或是能源出现之前,如果你需要注重程序的运行性能和开发效率,并更关注程序的运性能,那么,应该首选 C++。这就是iOS开发也支持C++的原因。

今天的C++11中不但有更多更不错的东西,而且,还填了更多原来C++的坑。(参看:C++11 WikiC++ 11的主要特性

 

总结

  • C++并不完美,但学C++必然让你受益无穷。
  • 是那些不合格的、想对编程速成的程序员让C++变得坑多。

最后,非常感谢能和“@简悦云风”,“@淘宝诸霸”,“@Laruence”一起讨论这个问题!无论你们的观点怎么样,我都和你们“在一起”,嘿嘿嘿……

(全文完)


关注CoolShell微信公众账号和微信小程序

(转载本站文章请注明作者和出处 酷 壳 – CoolShell ,请勿用于任何商业用途)

——=== 访问 酷壳404页面 寻找遗失儿童。 ===——
好烂啊有点差凑合看看还不错很精彩 (40 人打了分,平均分: 4.65 )
Loading...

C++的坑真的多吗?》的相关评论

  1. > 哦,这是我见过的最肤浅的语言比较:“我经常使用的A语言能做xxx,而B语言竟然不提供这支持——B语言竟然不能让我使用A语言的思考方式来使用它,B语言真实渣”。很遗憾,你似乎并没有理解generic typing,对于习惯了动态语言思维的人而言,将其看作一种静态的duck typing其实是很方便的,而SFINAE只是一个静态的“method missing”罢了。

    我哪说了C++是渣?C++是渣的话我也不可能用C++作为第二语言吧。
    不过C++对于新手来说学习成本太高,而且很容易写出Shit一样的代码。
    至少我没听过有人说“这个不合格的Python程序员写出来的代码太恐怖了”。
    Python这个例子确实举得不好,的确Python也有很多问题。
    不过你不能否认反射机制确实很有用。而且你要是说语言比较没有意义的话,
    那boost::parameter费尽心思把python中的命名参数引入C++完全是做无用功咯。

    >> 实际上C++完全可以设计成::
    >> []min(x, y) { return x 很高兴C++不是由你来设计,否则它的坑一定比现在多十倍…

    事实上这不是我设计的,这是C++标准委员会成员Dave Abrahams设计的。
    而且他还在Clang编译器上实作了以上语法。
    http://github.com/dabrahams/clang
    你不能否认它的设计相当漂亮吧。其实Python那个例子也是他举的。。。

    > 你是说比用强制缩进来体现代码逻辑还奇特?语言评论帖里总会出现各种沙文主义的言论,真是有意思的现象。

    强制缩进和强制函数式编程根本有天壤之别吧。
    强制缩进毕竟出发点是好的,强制函数式编程完全就是模板的一个副作用。
    别说什么模板元编程中变量当然不能改变这种话,
    世界上其他的典型函数式编程语言,比如Haskell,变量不照样可以赋值。
    而且你想Python Doctest不也是在程序运行前就进行了求值么,
    虽然Python中没有编译期的说法。

    > Concept被否决是因为现在的设计还不够成熟,出错信息的设计不包含在C++的设计当中,实际上很少有哪个语言的出错信息对新手用户是友好的。

    的确很多语言设计时候没考虑出错信息。可是Java出错信息远比C++友好。
    你有没有试过 std::list a; std::sort(a.begin(), a.end());

    > 我真是佩服你的自大,Andrei本人作为有影响力的一员,你认为…我想我还是省略下面的话比较好…

    的确,认为SmartPtr比shared_ptr好只是我个人的想法,也许其他人不这么看。
    我猜测C++标准委员会选用shared_ptr部分原因可能是认为SmartPtr设计过与复杂。。。
    我感觉Andrei本人就对SmartPtr标准化兴趣不大,
    而且他的竞争对手可是Boost这个C++标准委员会自己的东西。
    所以你不能说Andrei的想法一定很重要。

    > 你其实完全不熟悉STL,何必硬要凑上呢?你的评论洋洋洒洒,但总结起来只有一句话:我不熟悉or我不喜欢==不好。

    其实我老早就觉得把STL完完全全从C++标准中剔除将是一件大快人心的事情,
    我也没说过STL不好,我只是说我不喜欢。
    虽然用起来还是满方便的,不过尽管这玩意儿极大提高了生产力,但还能做到更好。
    而且不止我一人,STL的确争议性很大(可参见wikipedia上的批评)。
    据我所知Linus就抱怨过。

    > 这个提议不错,不过string被人诟病的难道不是成员函数太少?

    我觉得你更不熟悉STL。。。
    Herb Sutter就抱怨过string可以作为设计的反面教材。
    http://www.gotw.ca/gotw/084.htm

    > 你是说像Java那样?请问你要一个有公共基类的STL容器准备有何妙用?

    那你告诉我 Java 为何要那么设计?

    > 相信我,如果真的做了这样的设计,你一定会口风一转改为声讨C++设计复杂,还需要用户做许多不必要的决定,我想你这时候光顾喷的爽已经忘记你刚刚还称赞“Less is More”来着。

    我抱怨的是C++语言本身过于复杂,至于STL或Boost这种库倒是无所谓。
    好吧我承认当时确实喷得很爽,有些话可能的确没有仔细推敲。。。

    > 你所谓的继承机制是OO Diagram,而对于Generic Diagram的STL来说,需要的只是一个typename T而已。当然你对泛型了解的肤浅早已暴露,所以不怪你。

    STL没必要继承不意味着不能给OO使用者提供帮助,而且又没有抽象惩罚。

    @YY

  2. 没有完美的语言,语言的坑不是坑,是特性。
    在没有搞懂程序进程/线程和操作系统调度的影响之前,在没有理解过程式语言的开发特点和面向对象的优点之前,在没有体会面向对象开发方法的好处和语言本身的各种特性以及影响之前,在不能保证文档的可读性和工程的可维护性之前,不要轻易使用OOL开发,否则坑没法填。

  3. 这篇文章的出现在这里真的让我有些意外。语言之争很常见,不过没想到这次竟然是因为有人说c++比c坑多了……拿去和java、c#比都更相似,和c比的话那就完全不明所以了,如果只写c程序,c++一样支持,c++提供了c没有的更多特性,这俩就不该放在一起比。而且实际生产中,就算是c++和java比也不是这么比的,比的是哪个语言更能胜任当前的开发需求、人员技能更熟练。个人认为这种对语言的纯粹比较是非常——浪费时间的,这种问题我一般都一笑带过。楼主被卷入这样的问题中真是辛苦了 :)

  4. @Rasefon
    判定一个语言是否成功第一条原则不在于好不好用,第一条原则在于某些领域是否有大量成功案例,第二条才是看语言好不好用,C#除了开发企业应用(因为企业应用体验差一点也没关系,功能满足就ok)外,桌面软件领域用C#开发的,具我所知,流行点的只有飞信,但后来也改成C++了,因为体验问题。
    我觉得微软极力推广的.net战略算是失败了,搞了10年了,在自家的windows平台上桌面开发都搞不定,再加上
    现在进入云计算,动则上百台服务器,哪个厂商会用价格不菲的windows server作服务器?这样发展下去,.net上的语言适用范围是越来越小了。

  5. 其实博主,用填坑来描述语言的发展,我觉得不是很妥当

    任何技术的发展根本目的,并不是否则老的技术而去发展新的技术,

    说到底是人类追求方便,舒适的前提

    好比汽车,刚开始的汽车,是纯机械的,无任何电子自动化装置

    后来为了追求舒适,而增加了各种电子装置,又比如手动挡到自动挡的发展,

    但本质还是机械!

    但开过老式汽车的对汽车的内部构造的了解,绝对比如今开车的要深入的多!

    面向对象和面向过程难道真的是天壤之别?我看未必,你再怎么OO,也要过程吧?所谓过程就是办事的先后逻辑,

    我就不信,谁实现个人这个对象,然后提供吃饭的接口,内部实现不是先张嘴,后送饭的,这个先后逻辑就是过程!

  6. @Matrix
    坑很恰当啊。就是容易让人栽倒的地方。
    好的语言,不会让任何人栽倒(就像OA、流程管理系统,用户想犯错都不可能);
    C++就是不仅新手会栽倒,中手都会栽倒。
    这就是一个语言的不好(而不是对具体某个人好不好)的地方了,因为你不能要求每个使用者都是高手、对本质/内部构造深入了解

  7. 看多了linux内核的代码,对c++的多态,继承,真不怎么感冒。c++ template想法挺不错。

  8. haitao :
    @Matrix
    坑很恰当啊。就是容易让人栽倒的地方。
    好的语言,不会让任何人栽倒(就像OA、流程管理系统,用户想犯错都不可能);
    C++就是不仅新手会栽倒,中手都会栽倒。
    这就是一个语言的不好(而不是对具体某个人好不好)的地方了,因为你不能要求每个使用者都是高手、对本质/内部构造深入了解

    不可能的有这种什么人都不会栽倒的语言的,那样的话,你我还有饭吃吗?

  9. namespace 及 class 名称带来mangling的麻烦,当然这个不完全算是c++的问题,这是为了兼容以前的C库和工具造成的,但毕竟也是问题

    用const/inline/template代替了宏,因为一些本身的问题,现在宏在cpp里面的一些关键地方还是离不开

    用引用代替指针,这个造成的问题也不少啊,因为它不算真的引用,就是个指针假装的

    封装很多时候还不如POD类型直接

    RAII绝对要赞,C++我最欣赏这个了

    STL的坑也不少,不是看了API就能用的。所以还有Effective STL

    异常就不用说了,产品代码用了就死翘翘。

    总的来说在写程序时C++还是比C方便很多,仅仅是少写些代码,设计上基本都差不多。Linus说关键的是设计我非常赞同,C++程序员容易卡死在奇技淫巧还有面向对象中,张口闭口这个类那个类的,而不是这个功能那个功能。

    为什么C++的不合格程序员那么多,因为没有C++的话,他们基本就是不合格的C程序员,因为本来就是不合格的程序员,碰巧选择了C++而已,现在不合格的Java程序员应该也不少。

  10. 你得到了500%东西,但却只多了10%的坑,多值啊。 这个觉得不太赞同:1 这个数值是哪来的,为何不是多了600%的坑,这个不太靠谱啊。东西也多的那么夸张吧:) 如果说少敲了80%的代码不太信啊。2 语言的复杂性某种意义上算是复利,在每个点上增加了复杂性,导致整体的复杂性不是线性的增加,而是指数啊。3 我觉得用C++,规范及审查的重要性比C和Java大得多,很多情况用好C++的一个子集就好了:)

  11. 工作2年,最深的感受就是,不合格的程序员太多了!也许我就是其中之一,但是至少,我还是会经常注意学习和反省自己的问题。可从工作经历来看,用C语言项目里都能有如此多的坑,如果用C++,那后果真是不堪设想……
    正所谓不怕神一样的对手,就怕猪一样的队友!

  12. @Matrix
    那当然是理想情况,是一个语言的最高目标。
    但是,如果把人、项目都分级,针对不同水平的人和不同难度项目的各种组合,看看语言是不是坑,
    统计一下(如果加权不同水平的人和不同难度项目的百分百,就更准了),就知道这个语言的好坏程度了

  13. haitao :
    @Matrix
    那当然是理想情况,是一个语言的最高目标。
    但是,如果把人、项目都分级,针对不同水平的人和不同难度项目的各种组合,看看语言是不是坑,
    统计一下(如果加权不同水平的人和不同难度项目的百分百,就更准了),就知道这个语言的好坏程度了

    你的比喻本身就不恰当,OA,流程管理系统,这些是什么?是应用,应用是谁写的?是程序员用某种语言写的,所有应用的操作都是在程序员设计好的逻辑框架下的,否则就是BUG,明白吗?除非是像生化危机里邪恶的实验室某些特殊要求,程序才会设计自毁功能,否则用户只能按照应用的说明书来操作。

    那么再说下语言的本质,语言的本质是告诉CPU该干啥,你再高级的语言,到最后翻译成的CPU指令都是差不多的(在干相同的事的前提下,当然了,某些语言生成的冗余指令会更多),CPU是不知道吃饭要先张嘴的,所以越底层的语言越容易犯错,不是坑太多,而是太自由!而越高级的语言对底层的细节封装的就越隐蔽,程序员基本无法控制,当然绝大多数无需控制,可取所需而已!

    如果你非要把自己限制在一个框架下,完全按照说明书去办事,随便找个人培训下就好了,这也可以解释,为什么街上都是JAVA,.NET等培训班,而很少见C培训班,所以你例举的例子根本不对!

  14. C++在背后帮程序员默默做了很多东西,在C中,程序员们要自个搞定大多数东西。所以坑多很正常。其实C++最大的坑就是没一个1)符合工业标准, 2)跨平台, 3)广泛认可的库。比如,有时你不得不在BSTR,wstring,string和char
    *之间变来变去。

    事实上有坑也没啥,掉进去一次,大多数人就不会在掉进去了。C++现在的处境挺尴尬的,拼性能拼不过C,拼开发效率又拼不过C#。至少在PC上,C++未来的路会越来越窄。我没什么手机开发的经验,suttre关于省电的观点,听起来是挺有道理的,但这仍然需要有足够好的infrastructure支持。

    在windows平台上,我看好C和C#,C++不会退出舞台,它有它自己的专属领域,但属于C++的时代已经过去了。

  15. java对于C++的进步还有一点,就是取消了头文件机制.
    这是个伟大的进步!关于头文件的各种坑,各种纠结,都可以抛之脑后了…

    对于C++,它只是为C的坑提供了一些替换方式,但是丫从来就没有把这些坑填上!
    C++项目里一样肆无忌惮地跑着C的各种陋习,C和C++风格的混合让情况变得更加糟糕…
    也许这只是风格的问题.
    但是我们可以控制我们自己的代码风格,却没法控制我们用的库,我们的相关模块的风格.
    所以我们不得不面对风格不一致带来的各种各样的坑…
    C++的坑可不止是C加上一些,而是乘上一些…

  16. 哈哈,我也有过在注释中很愤怒的写FUCK,甚至命名为FUCK的时候。
    呵呵,我是用C的,但没真正使用过其他语言,不做其他评论,和陈老师一样,仅仅幽默幽默

  17. @Matrix
    不同层次,但是类比一样:
    企业用户,是程序员设计好的逻辑框架下操作,一有低级错误,流程能自动发现;
    程序员,是在语言设计者设计好的逻辑框架下写代码,一有低级错误,编译器能自动发现。
    企业用户要办A业务,却新增了一个B业务,那是流程无法发现的。
    程序员要完成A需求,却写了做B事情的代码,编译器也无法发现的。
    但是,好的语言能尽量不会让正常、中级(甚至初级)的程序员不会发生:想完成A,代码却是做B的情况。

  18. 我觉得 C++越来越高效 他的效率已经可以和JAVA .NET等语言媲美 , 因为有了BOOST 等库 还有C++11 的新标准 。

  19. haitao :
    @baibaichen
    坑更多的是指似是而非,表面和实际不一致,才害人了。
    单纯的只有基本功能、功能原始,需要程序员从头开始,还是不算坑

    我真傻,真的。我单知道下雪的时候野兽在山坳里没有食吃,会到村里来;我不知道春天也会有——祥林嫂

    我真傻,真的。我单知道STL很酷,却不知道当把它编译成DLL时会捅漏子——某个悲摧的同事……

  20. @yanyongyuan “兼容C的链接”模型一直是C++的基础出发点和最让人头疼的地方。我觉着“头文件”这个机制来管理声明的一致性一直就是个70年代的基础机制,个人认为可以评价为C/C++开发中的“阿基里斯之踵”了。

  21. 砖家 :
    工作2年,最深的感受就是,不合格的程序员太多了!也许我就是其中之一,但是至少,我还是会经常注意学习和反省自己的问题。可从工作经历来看,用C语言项目里都能有如此多的坑,如果用C++,那后果真是不堪设想……
    正所谓不怕神一样的对手,就怕猪一样的队友!

    最后不是打dota的人常说的话么………………

  22. 这真是可惜,RAII管理资源非常适合那些类似“堆栈”模型(严格的后进先出)的应用。“利用源程序中的作用域规则管理资源”是个非常巧妙的思想。可惜这种用法需要联合静态类型,析构函数,还有一个比较严谨的作用与规则才能有效。我现在用Java写Eclipse的plug-in,偶尔需要一些动态的界面响应的时候(也可能是我UI设计的问题),管理图形资源的正确释放始终都是很麻烦的事情。@kraft

  23. boywhp :明显C更适合大型项目吧,至少操作系统内核代码目前还没有C++的@vincent

    你根本不知道内核代码为什么不首先选择C++来编写的原因,跟大项目不大项目无关,内核苛刻的运行环境,现在的C++实现还缺乏对其完善的支持——主要变现在很多高级特性产生的代码可能带来的内存分页问题,而C作为一种高级汇编在这种需要精确控制硬件资源…严格的来说,只要用C89能做的事情,C++都行,All Valid C Program is Valid C++ Program.

  24. ytj :

    @ytj

    > 哦,这是我见过的最肤浅的语言比较:“我经常使用的A语言能做xxx,而B语言竟然不提供这支持——B语言竟然不能让我使用A语言的思考方式来使用它,B语言真实渣”。很遗憾,你似乎并没有理解generic typing,对于习惯了动态语言思维的人而言,将其看作一种静态的duck typing其实是很方便的,而SFINAE只是一个静态的“method missing”罢了。
    我哪说了C++是渣?C++是渣的话我也不可能用C++作为第二语言吧。不过C++对于新手来说学习成本太高,而且很容易写出Shit一样的代码。至少我没听过有人说“这个不合格的Python程序员写出来的代码太恐怖了”。Python这个例子确实举得不好,的确Python也有很多问题。不过你不能否认反射机制确实很有用。而且你要是说语言比较没有意义的话,那boost::parameter费尽心思把python中的命名参数引入C++完全是做无用功咯。

    抱歉,在你的口中我只看到C++一无是处。不合格的程序员写的什么代码都恐怖,C也一样,Python也一样。C++正是对新手太友好了,以至于什么样的菜鸟都能动手写C++。反射有用所以就得有,那eval也有用,C++实现干脆集成一个C++编译器?语言的比较,如果是基于语言的设计优劣来比较很正常,正是因为太多人喜欢用惯有的思维方式驾驭所有语言,才会出现boost::parameter之流的常识。比如费劲心机用JavaScript的原型系统来模拟基于类的面相对象类型系统,感谢上帝,新版的EcmaScript终于为这帮只会用class语法的idiot引入了正式的class语法。

    >> 实际上C++完全可以设计成::>> []min(x, y) { return x 很高兴C++不是由你来设计,否则它的坑一定比现在多十倍…
    事实上这不是我设计的,这是C++标准委员会成员Dave Abrahams设计的。而且他还在Clang编译器上实作了以上语法。http://github.com/dabrahams/clang你不能否认它的设计相当漂亮吧。其实Python那个例子也是他举的。。。

    Dave,Andrei,Herb,Bjarne,随便是谁设计的,这都不是个好主意。请不要动不动抬出权威来吓人。[]语法是C++11为引入lambda特性而设计的。C++11的lambda是帮助程序员快速生成函数对象类定义的语法糖。换言之,此处这个你认为极妙的设计,看起来很美,但是带来的结果是什么?一个函数对象类的定义!老天,我们需要的是一个全局函数,你却给了我一个叫不出名字来的类定义!是的,你可以改造编译器,让它在此处做一些小动作,强行在这里生成一个函数——等等,怎么这个函数的参数没有类型,你说这里想要的是一个函数模板?对不起,C++11还不支持lambda模板…——是的,你可以继续hack编译器,直到得到你想要的结果,以及一份完全缺乏自洽,让人惊奇不断地,自相冲突的C++标准,啊哈,太好了,C++又有可以让你喷的地方了。

    > 你是说比用强制缩进来体现代码逻辑还奇特?语言评论帖里总会出现各种沙文主义的言论,真是有意思的现象。
    强制缩进和强制函数式编程根本有天壤之别吧。强制缩进毕竟出发点是好的,强制函数式编程完全就是模板的一个副作用。别说什么模板元编程中变量当然不能改变这种话,世界上其他的典型函数式编程语言,比如Haskell,变量不照样可以赋值。而且你想Python Doctest不也是在程序运行前就进行了求值么,虽然Python中没有编译期的说法。

    除了Brainfxxk,我不知道有什么语言的设计者出发点是不好的,模板本来就不是为了进行静态的函数式编程而设计的,刚好能被用来进行元编程只是一个美丽的巧合,拿一个“意外”和专门为函数式编程而设计的“故意”去比,实在是太有节操了。你说模板语法奇特?模板作为模板使用语法一点都不奇特,那只是你硬要用模板来做元编程罢了,实际上即使用模板做元编程,也不会别其它函数式语言奇特到哪里去。你希望的变量赋值,那是一个运行时副作用,你知道模板写成的元程序是什么时候运行吗?实际上赋值是存在的,只是你根本没明白模板元编程罢了。

    > Concept被否决是因为现在的设计还不够成熟,出错信息的设计不包含在C++的设计当中,实际上很少有哪个语言的出错信息对新手用户是友好的。
    的确很多语言设计时候没考虑出错信息。可是Java出错信息远比C++友好。你有没有试过 std::list a; std::sort(a.begin(), a.end());

    Java当然不会有这个问题,因为Java都没有泛型算法,也没有迭代器范畴层次结构。你没有遇到过Java的难缠的错误提示,仅仅只是因为你没有遇到过而已。

    > 我真是佩服你的自大,Andrei本人作为有影响力的一员,你认为…我想我还是省略下面的话比较好…
    的确,认为SmartPtr比shared_ptr好只是我个人的想法,也许其他人不这么看。我猜测C++标准委员会选用shared_ptr部分原因可能是认为SmartPtr设计过与复杂。。。我感觉Andrei本人就对SmartPtr标准化兴趣不大,而且他的竞争对手可是Boost这个C++标准委员会自己的东西。所以你不能说Andrei的想法一定很重要。

    C++标准委员会至少是遵循民主的形式进行决议的,我想结果即使不是最好,也不至于是太差,关于Andrei的个人影响力的话题没有材料佐证,就此打住吧。

    > 你其实完全不熟悉STL,何必硬要凑上呢?你的评论洋洋洒洒,但总结起来只有一句话:我不熟悉or我不喜欢==不好。
    其实我老早就觉得把STL完完全全从C++标准中剔除将是一件大快人心的事情,我也没说过STL不好,我只是说我不喜欢。虽然用起来还是满方便的,不过尽管这玩意儿极大提高了生产力,但还能做到更好。而且不止我一人,STL的确争议性很大(可参见wikipedia上的批评)。据我所知Linus就抱怨过。

    你不喜欢你可以不用,Linus is Bullshit.

    > 这个提议不错,不过string被人诟病的难道不是成员函数太少?
    我觉得你更不熟悉STL。。。Herb Sutter就抱怨过string可以作为设计的反面教材。http://www.gotw.ca/gotw/084.htm

    你的确对C++很无知,连STL的范畴都没有搞清楚,STL特指标准中Container Library,Iterator Library,Algorithm Library三章中涉及的部分,不是“标准库中的模板”就叫做“标准模板库”,尽管basic_string参照了Sequence Container设计,但它并不是STL的一部分。我是Herb的忠实读者,你不用贴gotw的文章出来给自己装声势。你可以好好看看你喷的帖子里的提议和Herb的批评是不是一回事。

    > 你是说像Java那样?请问你要一个有公共基类的STL容器准备有何妙用?
    那你告诉我 Java 为何要那么设计?
    Just because Joshua Bloch is an idiot. 好像在你的逻辑里Java的设计就是好的代名词一样…实际上Java也是典型的委员会设计,而且因为被SUN长期把持了JCP的领导权,很多在政治妥协下的并不那么好的设计成为JSR进入Java的标准体系,以至于另外一帮人不得不走Apache这个曲线来救国。

    > 相信我,如果真的做了这样的设计,你一定会口风一转改为声讨C++设计复杂,还需要用户做许多不必要的决定,我想你这时候光顾喷的爽已经忘记你刚刚还称赞“Less is More”来着。
    我抱怨的是C++语言本身过于复杂,至于STL或Boost这种库倒是无所谓。好吧我承认当时确实喷得很爽,有些话可能的确没有仔细推敲。。。

    你只是在抱怨你用C++用的不爽而已。

    > 你所谓的继承机制是OO Diagram,而对于Generic Diagram的STL来说,需要的只是一个typename T而已。当然你对泛型了解的肤浅早已暴露,所以不怪你。

    STL没必要继承不意味着不能给OO使用者提供帮助,而且又没有抽象惩罚。
    怎么会没有抽象惩罚?这样的设计使得多个属于不同概念的容器互相耦合成一团[此处省略若干字],简直是糟糕到底的呕吐物设计。OO使用者如果觉得C++不够OO应该去用Java,按你的要求,C++是不是还要像Java那样给所有的类提供一个Object基类?真是不可理喻。

  25. 上一篇排版有些问题,请皓哥删掉吧。

    ytj :

    > 哦,这是我见过的最肤浅的语言比较:“我经常使用的A语言能做xxx,而B语言竟然不提供这支持——B语言竟然不能让我使用A语言的思考方式来使用它,B语言真实渣”。很遗憾,你似乎并没有理解generic typing,对于习惯了动态语言思维的人而言,将其看作一种静态的duck typing其实是很方便的,而SFINAE只是一个静态的“method missing”罢了。
    我哪说了C++是渣?C++是渣的话我也不可能用C++作为第二语言吧。不过C++对于新手来说学习成本太高,而且很容易写出Shit一样的代码。至少我没听过有人说“这个不合格的Python程序员写出来的代码太恐怖了”。Python这个例子确实举得不好,的确Python也有很多问题。不过你不能否认反射机制确实很有用。而且你要是说语言比较没有意义的话,那boost::parameter费尽心思把python中的命名参数引入C++完全是做无用功咯。

    抱歉,在你的口中我只看到C++一无是处。不合格的程序员写的什么代码都恐怖,C也一样,Python也一样。C++正是对新手太友好了,以至于什么样的菜鸟都能动手写C++。反射有用所以就得有,那eval也有用,C++实现干脆集成一个C++编译器?语言的比较,如果是基于语言的设计优劣来比较很正常,正是因为太多人喜欢用惯有的思维方式驾驭所有语言,才会出现boost::parameter之流的常识。比如费劲心机用JavaScript的原型系统来模拟基于类的面相对象类型系统,感谢上帝,新版的EcmaScript终于为这帮只会用class语法的idiot引入了正式的class语法。

    >> 实际上C++完全可以设计成::>> []min(x, y) { return x 很高兴C++不是由你来设计,否则它的坑一定比现在多十倍…
    事实上这不是我设计的,这是C++标准委员会成员Dave Abrahams设计的。而且他还在Clang编译器上实作了以上语法。http://github.com/dabrahams/clang你不能否认它的设计相当漂亮吧。其实Python那个例子也是他举的。。。

    Dave,Andrei,Herb,Bjarne,随便是谁设计的,这都不是个好主意。请不要动不动抬出权威来吓人。[]语法是C++11为引入lambda特性而设计的。C++11的lambda是帮助程序员快速生成函数对象类定义的语法糖。换言之,此处这个你认为极妙的设计,看起来很美,但是带来的结果是什么?一个函数对象类的定义!老天,我们需要的是一个全局函数,你却给了我一个叫不出名字来的类定义!是的,你可以改造编译器,让它在此处做一些小动作,强行在这里生成一个函数——等等,怎么这个函数的参数没有类型,你说这里想要的是一个函数模板?对不起,C++11还不支持lambda模板…——是的,你可以继续hack编译器,直到得到你想要的结果,以及一份完全缺乏自洽,让人惊奇不断地,自相冲突的C++标准,啊哈,太好了,C++又有可以让你喷的地方了。

    > 你是说比用强制缩进来体现代码逻辑还奇特?语言评论帖里总会出现各种沙文主义的言论,真是有意思的现象。
    强制缩进和强制函数式编程根本有天壤之别吧。强制缩进毕竟出发点是好的,强制函数式编程完全就是模板的一个副作用。别说什么模板元编程中变量当然不能改变这种话,世界上其他的典型函数式编程语言,比如Haskell,变量不照样可以赋值。而且你想Python Doctest不也是在程序运行前就进行了求值么,虽然Python中没有编译期的说法。

    除了Brainfxxk,我不知道有什么语言的设计者出发点是不好的,模板本来就不是为了进行静态的函数式编程而设计的,刚好能被用来进行元编程只是一个美丽的巧合,拿一个“意外”和专门为函数式编程而设计的“故意”去比,实在是太有节操了。你说模板语法奇特?模板作为模板使用语法一点都不奇特,那只是你硬要用模板来做元编程罢了,实际上即使用模板做元编程,也不会别其它函数式语言奇特到哪里去。你希望的变量赋值,那是一个运行时副作用,你知道模板写成的元程序是什么时候运行吗?实际上赋值是存在的,只是你根本没明白模板元编程罢了。

    > Concept被否决是因为现在的设计还不够成熟,出错信息的设计不包含在C++的设计当中,实际上很少有哪个语言的出错信息对新手用户是友好的。
    的确很多语言设计时候没考虑出错信息。可是Java出错信息远比C++友好。你有没有试过 std::list a; std::sort(a.begin(), a.end());

    Java当然不会有这个问题,因为Java都没有泛型算法,也没有迭代器范畴层次结构。你没有遇到过Java的难缠的错误提示,仅仅只是因为你没有遇到过而已。

    > 我真是佩服你的自大,Andrei本人作为有影响力的一员,你认为…我想我还是省略下面的话比较好…
    的确,认为SmartPtr比shared_ptr好只是我个人的想法,也许其他人不这么看。我猜测C++标准委员会选用shared_ptr部分原因可能是认为SmartPtr设计过与复杂。。。我感觉Andrei本人就对SmartPtr标准化兴趣不大,而且他的竞争对手可是Boost这个C++标准委员会自己的东西。所以你不能说Andrei的想法一定很重要。

    C++标准委员会至少是遵循民主的形式进行决议的,我想结果即使不是最好,也不至于是太差,关于Andrei的个人影响力的话题没有材料佐证,就此打住吧。

    > 你其实完全不熟悉STL,何必硬要凑上呢?你的评论洋洋洒洒,但总结起来只有一句话:我不熟悉or我不喜欢==不好。
    其实我老早就觉得把STL完完全全从C++标准中剔除将是一件大快人心的事情,我也没说过STL不好,我只是说我不喜欢。虽然用起来还是满方便的,不过尽管这玩意儿极大提高了生产力,但还能做到更好。而且不止我一人,STL的确争议性很大(可参见wikipedia上的批评)。据我所知Linus就抱怨过。

    你不喜欢你可以不用,Linus is Bullshit.

    > 这个提议不错,不过string被人诟病的难道不是成员函数太少?
    我觉得你更不熟悉STL。。。Herb Sutter就抱怨过string可以作为设计的反面教材。http://www.gotw.ca/gotw/084.htm

    你的确对C++很无知,连STL的范畴都没有搞清楚,STL特指标准中Container Library,Iterator Library,Algorithm Library三章中涉及的部分,不是“标准库中的模板”就叫做“标准模板库”,尽管basic_string参照了Sequence Container设计,但它并不是STL的一部分。我是Herb的忠实读者,你不用贴gotw的文章出来给自己装声势。你可以好好看看你喷的帖子里的提议和Herb的批评是不是一回事。

    > 你是说像Java那样?请问你要一个有公共基类的STL容器准备有何妙用?
    那你告诉我 Java 为何要那么设计?

    Just because Joshua Bloch is an idiot. 好像在你的逻辑里Java的设计就是好的代名词一样…实际上Java也是典型的委员会设计,而且因为被SUN长期把持了JCP的领导权,很多在政治妥协下的并不那么好的设计成为JSR进入Java的标准体系,以至于另外一帮人不得不走Apache这个曲线来救国。

    > 相信我,如果真的做了这样的设计,你一定会口风一转改为声讨C++设计复杂,还需要用户做许多不必要的决定,我想你这时候光顾喷的爽已经忘记你刚刚还称赞“Less is More”来着。
    我抱怨的是C++语言本身过于复杂,至于STL或Boost这种库倒是无所谓。好吧我承认当时确实喷得很爽,有些话可能的确没有仔细推敲。。。

    你只是在抱怨你用C++用的不爽而已。

    > 你所谓的继承机制是OO Diagram,而对于Generic Diagram的STL来说,需要的只是一个typename T而已。当然你对泛型了解的肤浅早已暴露,所以不怪你。
    STL没必要继承不意味着不能给OO使用者提供帮助,而且又没有抽象惩罚。

    怎么会没有抽象惩罚?这样的设计使得多个属于不同概念的容器互相耦合成一团[此处省略若干字],简直是糟糕到底的呕吐物设计。OO使用者如果觉得C++不够OO应该去用Java,按你的要求,C++是不是还要像Java那样给所有的类提供一个Object基类?真是不可理喻。

  26. @haitao
    我的意思,失败是成功它老母。很多时候说C++坑多,我感觉是说C++难学而已。不可否认,C++太复杂了,像模板元编程这种技术,大多数程序员是用不到滴。

  27. 周六日, 两天看完了C++程序设计(英文). 以为自己能写C++, 会了. 然后随手拿起 Effective C++, 这不是坑爹吗? 
    Effective C++ 和 C++ 程序设计的两个C++根本既不是一个语言....
    起码C 和 JAVA 你看完语法. 写程序基本没有任何问题呀(不说C和复杂的宏). 大部分情况下按照API 写就可以了.

    C++我真的伤不起...现在蛋疼死我了.
    起码这里可以看出 C++对新手非常不友好(你可以说我们不需要新手, 除非某些人一入门就是老手).
    一门语言让你天天关心在语言层面上, 而不是逻辑层面. 这个语言能说有多好呢?

    (一个新手对C++的感悟) 

  28. C很强大,C++也很强大,JAVA也很强大,OK,都学吧,没必要争来争去,不要因为道听途说而欺骗了你的认知。

  29. @mike
    要考啥级? 我是JAVA的, 学了几周C语言, 可以开发linux的模块. 问题是我现在学了C++, 我竟然怕到不敢写代码…就怕遇到某个雷.

  30. @Liu1809
    哈哈, 其实差不多. 我是晚上翻的, 第二天早上看完的. 这本书真的很不错(对于C++入门来说, 例子也很简单). 但是effective c++ 太可怕了.

  31. 怎么感觉RAII 只不过是C++的一块遮掩布而已.. 难道不就是finally 字段就能解决的问题吗? 或者是jdk 7的资源管理方式.

    而且某个时候还要放到一个大括号里面(或者智能指针).

    C++比JAVA 更接近底层, 但是却比C复杂那么多(以至于没有一个编译器能实现它所有的特性). 如果业务开发真的不是好选择..

  32. 这就好像飞机一样,开飞机很难,开飞机要注意的东西太多太多,对驾驶员的要求很高,但你不能说飞机这个工具很烂,开飞机的坑太多。

    这个比喻真是太好了!

    是否可以引申一下, 现在太多的程序员或者公司都想去开飞机,却不知道其实汽车已经足够他们用了,或者知道,但看到别人在开,自己不开觉得没档次。 (这里说的汽车也不是特指C)

  33. L :
    这就好像飞机一样,开飞机很难,开飞机要注意的东西太多太多,对驾驶员的要求很高,但你不能说飞机这个工具很烂,开飞机的坑太多。
    这个比喻真是太好了!
    是否可以引申一下, 现在太多的程序员或者公司都想去开飞机,却不知道其实汽车已经足够他们用了,或者知道,但看到别人在开,自己不开觉得没档次。 (这里说的汽车也不是特指C)

    这个比喻不对… 你怎么确定C++是飞机, 其他的是汽车? 就像楼主说的, 带了500%好处, 只有10%的坑, 这个怎么统计的?

  34. @xiaoyu
    如同博文所说,C++有500%的特性,C和Java加起来还多。若会了C++,Java,C很简单
    工作的人别称自己新手,新手有的是时间学

发表评论

电子邮件地址不会被公开。 必填项已用*标注