C++的坑真的多嗎?

openkk 12年前發布 | 33K 次閱讀 C/C++

        先說明一下,我不希望本文變成語言爭論貼。希望下面的文章能讓我們客觀理性地了解 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++ 程序員淡定

C++的坑真的多嗎?

        不要太糾結上圖,只是輕松一下,我沒那么無聊,讓我們來看點真正的論據。

        相信用過 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++的坑真的多嗎?

        今天的C++11中不但有更多更不錯的東西,而且,還填了更多原來 C++ 的坑。(參看:C++11 WikiC++ 11 的主要特性

 C++的坑真的多嗎?

        總結

  • C++并不完美,但學 C++ 必然讓你受益無窮。
  • 是那些不合格的、想對編程速成的程序員讓 C++ 變得坑多。

        最后,非常感謝能和“@簡悅云風”,“@淘寶諸霸”,“@Laruence”一起討論這個問題!無論你們的觀點怎么樣,我都和你們“在一起”,嘿嘿嘿……

 本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!