從職業玩家角度看,C++有多難?

從職業玩家角度看,C++有多難?

對於多數初學者來說,C++ 的難度並不在語法語意等語言層面,而是沒學過 C++ 所支持的面向對象、泛型編程、元編程、函數式編程等不同編程範式,以至於標準模板庫(STL)裡關於數據結構和算法的知識,甚至一些部分與計算機架構、編譯原理、操作系統等知識相關。學習 C++ 可以同時學習、實踐這些相關知識。

按面試經驗,本科同學們的 C++ 水平真是天差地別的。你能學到什麼程度,就看你的努力程度了。

從職業玩家角度看,C++有多難?

1個月: 都說C++難,但聰明如我,一個月就讀完了C++ primer,我看這C++也不過如此.

3個月: 原來之前一直在用C++語法寫C... 開始正式學習C++...

1年: 今天花一下午一定要琢磨明白這段代碼啥意思...

2年: C++太他媽難了, 發明C++的可以吃X去了

3年: 這輩子絕對不能繼續搞C++了,珍惜生命,遠離C++

4年: ......

5年: 終於神功初成, 大家好,我是C++專家,疑難雜症請問我

7年: 我比較擅長XXX這塊,其他方面我是外行

10年: 我有一定的C++基礎...

從職業玩家角度看,C++有多難?

由於現在懂C++的人少,很多人對C++有點望而生畏,這種誤解需要糾正一下。

(補充:C++在很多重要領域都是不可替代的,“有用還是沒用”的問題根本不需要考慮。)

1、雖然C++的上限非常高,但是分階段性逐步學習是沒有問題的。

按照流行的說法,C++集成了多種編程範式,包括 過程式編程、面向對象、泛型、函數式等等(我總感覺實際不止4種)。

而且,根據軟件的原理來說,只需要一種編程範式(比如過程式),就已經可以解決所有問題了,從數學上來講這麼多的範式並不是必要的。實際上,只要你掌握了基礎的過程式編程,再加一半面向對象的技術,就已經可以解決相當多問題了。

比如很早以前MFC還流行的時候,大部分人用的C++也只不過就是OO那些東西而已,照樣做出了豐富多彩的應用程序。

2、如何分階段學習

進行長期的C++學習,很像是攀巖,雖然看似學習曲線陡峭,但是每一步都是有根有據的,並不會一下子飛起來。

從職業玩家角度看,C++有多難?

1、學習C++並不需要從C開始,但是指針、函數等等基本的使用務必做到100%熟悉。這也是學習C語言最強調的一點。C++對類型的限定更為嚴格,相對C來說反而不會很“跳脫”,可能反而好學一些。

2、之後就是class相關的一部分,廣泛來說就是OO那一套東西。基本的有類、對象,到最後不過也就是多態而已。這一部分還是沒什麼太難的東西,多思考、多實踐即可。

3、再往後遇到模版、泛型。雖然泛型編程這部分上限很高,但是下限也很低。你只要能正確地利用泛型擴展class的功能、提高易用性,就算是懂了一半;而且這一半一點也不難,照貓畫虎即可學會。

4、到這裡同時還會遇到STL和常用容器,往淺說,你只要知道什麼時候用什麼容器、怎樣用好容器;往深說,你要儘可能多瞭解多種容器的實現原理、內存佈局和規則等等。一步一步深入理解。

5、這時候你就已經來到一個“初級C++程序員”的臺階上了,再往後最好不要閉門造車,還是要兼顧學習和項目實踐,才能更穩定地進一步發展,避免走歪。

從職業玩家角度看,C++有多難?

可能遇到的麻煩

只要一步一步來,一年左右時間應該能基本達到上面所說的水準,但在這個過程中可能遇到一些比較大的坎,比如:

  1. 知道“宏”怎麼用,但是複雜的看不懂。
  2. 知道面向對象怎麼寫,但是不能合理設計、使用OO
  3. 指針、引用、對象、const、運算符重載都懂,但是放在一起就亂了。
  4. 寫出來的程序內存管理比較亂,有崩潰或者洩露不知道怎麼改。

等等這些問題都是會發生的,要解決這些問題只要記住一點——不要在意學習快慢,在細節上花10倍時間是值得的,只要每個地方都花時間搞懂,那就離大牛不遠了。你在知乎上看到的很多C++大牛,都是在這方面有意無意地花費了海量的時間,自然就成為高手了。

從職業玩家角度看,C++有多難?

C++雖然上限很高,但是並沒有多麼可怕,初級有初級的玩法、高級有高級的玩法。只要一步一步做下去,邊學習邊使用並不會覺得很難。

對於大學生,只要合理投入時間,就一定能達到一個合格的程序員水準。具體有多高水平,一是看你的努力程度,二是看有沒有抓住機會多實踐(比如畢設、大作業、教研項目等等都是機遇)。

現在積累的越多,在未來就越有不可逾越的壁壘,加油。

從職業玩家角度看,C++有多難?

首先,你想靠c++來混飯吃,這個想法很有前途。我是大學快畢業的時候才學c++,畢業的時候找的一個碼農的工作但是用的不是c++,於是就一邊工作一邊學習c++。我的性格比較懷舊,一旦學了什麼,就想用一輩子,我當年就覺得,如果有什麼語言可以混飯吃混一輩子,那隻能是c++。

現在的工作已經用了十年c++了,十幾年前買的《c++標準程序庫》現在已經已經升級到第二版,從c++98變成了c++11。我相信,再過十年,只要我還在做碼農的工作,c++還是能夠養活我。(下圖四本書,購買時間分別為:2017、2004、2003、2016)。

從職業玩家角度看,C++有多難?

學c++的過程就如同在是爬一座高高的大山,是一個漫長的過程,不僅僅是找工作前要學,工作過程中還是要不斷地學習,需要興趣、耐心。你現在大三,為了找工作,不僅僅是需要學習基本的c++/stl,還要學習一些其它的知識,比如說網絡、算法、操作系統、數據庫,每樣都要知道一些。

從職業玩家角度看,C++有多難?

cpp裡最簡單的部分就是c with class,先學到這種程度,你就能處理大部分需求了。真的很大的程序,比如linux內核,mysql, pg, gcc, 基本都是這麼寫的,所謂c語言不能寫大型軟件完全是謠言。真的寫一輩子c with class你也能在另一個世界裡找到秩序。幹什麼幹久了都能屌的一逼的。

好多人一開始看就是cpp primer啥的,一棍子打蒙,回答了這個問題的大部分人都是有cpp知識死角的,無死角的幾乎沒有。然後寫比較複雜的項目的時候再去看看虛函數和多態,想想怎樣使用設計模式剝離機制和策略。這個就是oox啦。用cpp實踐oox。這個是現代大型軟件開發的經典套路了。

然後還有啥,寫通用庫,模版元編程啦。這個需要很長時間訓練和思考。

函數式,cpp這些方面還在路上,函數式本身是個超級大坑。

所以我建議不要一下子學習那麼多,你可以根據自己的工作環境,先學一個方面,深入了,再慢慢豐滿羽翼,一下子把cpp primer搞一遍是有點殘酷的。如果要讀書,cpp primer案頭書。cpp編程思想和cpp語言的設計與演化可以看看。其它可以wiki。

我覺得cpp編程範式太多了,相當於在學好幾門語言,所以每個方面都很水很正常了。可以先集中一種範式忽略其它工作。慢慢需要時再逐漸訓練和充實自己。

從職業玩家角度看,C++有多難?

先把C語言搞紮實(這會逼著你把很多基本的計算機問題弄清楚),再學C++,每學一個語法點都要想清楚他為什麼這樣設計和實現,如果自己用C語言去實現應該會用什麼樣的方法來實現,如果彙編學的好還可以去閱讀反彙編的結果來看看編譯器到底是怎麼實現的(當然有反編譯器來輔助閱讀也不錯)。

當你學會自己用C或者彙編來實現虛函數,成員函數指針這些的時候,,,C++的二進制上的常用設計手段和設計準則對你沒有太多秘密了,只剩文法上的各種新標準新語法了。基本上你應該要能做到看到這些新語法,都能知道他背後的二進制秘密。所以基本不會怕新標準中的改革了。

說說我眼中的c++11後的一些新語法的創新點

  1. 顯式的右值語義:文法創新
  2. (棧上)變長數組:二進制創新,c++14趕緊又把它給廢了(感謝評論指正,c++11就沒采納)。
  3. 變長模版參數:文法創新
  4. lambda: 文法創新,幫你自動生成函數對象和捕獲變量的構造函數。
  5. c++20的協程(ts):二進制創新,c++唯二提供編譯器自動堆上分配內存保存數據的語法糖(第一個是異常)。

在理解好這些c++ 二進制密碼之後,對於如何實踐C++,避免最容易出問題的內存分配&訪問&回收問題,不會有特別大的困難了。但是有一些很成熟的內存使用高階範式還是值得單獨去學習和理解的。例如std::shared_ptr很好用,但是哪些時候類一開始定義時就應該選擇使用侵入式引用計數或者std::enable_shared_from_this呢(個人認為是那些可能會在成員函數里自己刪除自己且成員函數在設計中是通過間接隱式調用的對象)?

從職業玩家角度看,C++有多難?

C++之難不在於其語法的複雜性,也不在於二進制層面上語義的雜亂無章,更不在於玄妙得不食人間煙火的模板推導(模板元編程),這些都只是表象。本質上講,C++跟任何語言比,它很獨特很怪異(廢話,任何一種語言那個不特異)。

很多時候,C++給人的感覺就是,好像任何一種語言的特性(這話有點誇張),都可以在C++王國中,通過令人髮指的奇技淫巧,罄竹難書的花樣作死,最後終於可以在一定程度上模擬出來,但是模擬後的結果,又總是存在這樣那樣的不足,要麼因為內存管理,要麼因為反射的原因,總之,就是好像可以做一切事情,但最後終於做得不好。這個時候,猿猴要麼就直接撲上原生帶有這種特性的語言,要麼乾脆就完全捨棄,放棄治療,啥技巧也不用,返璞歸真,就老老實實一行代碼一行代碼、不厭其煩、不畏枯燥地一再寫地重複類似的功能。而C++自身的優秀特性(析構函數、內存管理、模板、多繼承等等),沒有任何一種語言整的出來,當然,也可以說,這些玩意都是為了解決C++自身製造出來麻煩,other語言s完全不care這些雜碎。難道,這些好東西就沒有一丁點價值了。

更令人難堪的是,迄今為止,C++業界就沒有出現過方方面面都讓人滿意的基礎庫,也即是性能(對c++猿來說,性能最重要)、可擴展性、易用性、安全性都經得起推敲。所有的通用庫、流行庫都存在這樣那樣的詬病,stl如是,boost如是,qt如是,……。所以,就開始有人(現在是普遍都持這種觀點啦,十幾年前還只是開始)懷疑了,為什麼其他語言出來不久,就馬上配套相應的官方基礎權威平臺框架庫,就算是C語言,也有標準頭文件庫,裡面也確實沒有可爭議之處。就C++諸多借口,遲遲交不出答卷。這一定是語言的問題,毫無疑問。就算不是語言的問題,你看看,幾十年下來,多少大牛,就搞不出來的東西,由此可見,C++有多麻煩,有多複雜,平常人hold得住嗎?

可是,基於C語言,C++多出來任何特性,都確確實實很有價值,用得好,的而且確,可以節省很多很多重複代碼。就算最讓人詬病的隱式類型轉換,雖然一不小心,就給猿猴驚喜,帶來理解上麻煩。但是,在可控的情況下,真的可以少寫煩心的代碼,某些場合,也是奇技淫巧的用武之地。好吧,既然low C都能寫出來基礎通用庫,反而高大上的C++就舉步維艱了。問題是,精緻的C代碼,到了C++舞臺上,馬上就備受一連串很有道理的指責,類型不安全啦,缺乏彈性啦,不夠易用性,甚至連性能(明明在C那裡就是極限了),也可以榨出汁來。既然你大C++這麼厲害,你行你上啊,少在這裡瞎逼逼。幾十年了,你換了多少次新馬甲,依然虛有其表,金玉其外。可以想象大C++的老臉有多紅啊。

所以說,這個世界的猿猴語言分為兩大類,C++與其他語言。其他語言稍微努力就能做出來很有群眾基礎的通用庫(不接受也不行,壓根就不讓你做文章,就不給你後門更好地實現),進而跑步進入共產主義,人生苦短。而C++看著其他語言的通用庫,就會瞎逼逼,指指點點,這裡不好,那裡不對,但是自己無論如何,就是隻能做出來小團體運用,自我陶醉的通用庫,這些所謂的通用庫,最後多半要被歷史潮流所淘汰。

當你廢了九牛二虎之力搞清楚了C++的對象模型(繼承、多繼承、虛繼承、異常、……),各種數據類型在內存中表示,還搞清楚不同編譯器的不同處理方式;興致勃勃搞起模板元編程從入門到放棄;預處理的偽圖靈完備也玩出翔來;將mfc操得體無完膚;對stl、boost也深挖祖墳以至深感失望(stl還好,boost真心爛);C++編譯器也被操得死去活來;……,這都有多少年過去了,依然感覺寫不好C++代碼,依然充滿疑惑,代碼寫來寫去,總是感覺寫的不對,似乎還可以提升,還可以提升,可以在犧牲性能、類型安全、彈性、易用性的前提下繼續加強性能、類型安全、彈性、易用性,你不知道C++的上限在哪裡。直到有一天,那一刻,終於到達彼岸。

對於普通用戶來說,C++最大的問題,就是缺乏一個高水準高質量的基礎通用庫,這個庫,首先要堅持住零懲罰抽象的底線,不管怎麼樣,都不得妥協,歷史的經驗證明,在這一點上退縮的基礎庫,最後都將導致整個設計框架上的冗餘,倒不僅僅只是因為性能的原因。其次,在性能、彈性、使用接口、類型安全等綜合方面都要取到很好的平衡點,也就是說用這個庫說人話的時候,其性能一定要不差,好用,有彈性,類型上用得不對,編譯器就不滿意。但是這個基礎庫又要像大C++語言本身一樣,充滿後門,只要願意,隨時都可以為了提升某一要素,可以犧牲任何其他要素(比如說為了性能,將使用接口、彈性上搞得很難看)。具體展開來說,這個基礎庫包括,完備的內存管理(支持一定程度的gc效果,其實就是多次分配,一次統一釋放);完備的運行時類型信息;極大地挖掘template的潛力;編譯期與運行期的無縫對接,二進制語義上的清晰。至於再具體來說,比如字符串設計,格式化,序列化,IO,侵入式的容器,迭代器,協程等,就是細微末節了。

顯然,以上述的要求來評判stl,顯然stl很不行的,雖然勉勉強強堅持住零懲罰的底線,但是總體來說,其性能、彈性、使用接口、類型安全的總體分數上是相當低的。1、竟然腦洞大開,將內存管理當做是容器的類型參數來操作,這樣玩的嚴重可怕後果,就不說stl的東西不能很好地用於動態庫,想要做有gc效果的內存管理也不好辦了;2、對模板的使用只停留在很低的層次上,本來可以提供更多更有力的抽象機制,比如非侵入式接口,比如消息,比如異構容器;3、迴避虛函數,迴避反射,導致stl的運行時類型信息很薄弱,進而導致垃圾的io stream實現,對面向對象的支持極差,也導致痛苦漫長的編譯過程;4、對於編譯期的豐富類型信息,只會用類型拭擦一招帶到運行期,導致到運行期時丟失了很多重要的信息;5、對於容器的二進制佈局,迴避,不花心思,所以二進制的複用效果很差;……,算了,對stl的不滿,簡直是說三天三夜也說不完。所以,以stl為基礎來寫代碼,能不一再反覆造輪子,寫代碼能愉快?

所以,C++的難,說到底,只是通用基礎庫的實現之難。C++的難,是C++專家的難題,並非普通用戶的麻煩。那麼,實現通用基礎庫的難度有多大,從C++面試至今三十多年,還沒出現過,你說會有多難呢?那麼,為什麼會這麼難呢?

一直以來,C++專家對C++的認識,一直停留在很低的層面上。面對著C++複雜龐大的類型系統,完全開放式的內存管理,直接操作機器的種種方便,威力無比的template,很醜陋又好像很重要很有作用的預處理,厚顏無恥的多繼承以及不定時炸彈的異常,這些東西造就了C++無限可能的同時,也造成了C++在打造基礎通用的極大困難。表面上存在無窮無盡的選擇,但是正確的路子,真心不多。一不小心,就面臨無窮無盡的細節上的考究,最後造出來的輪子,反而引入更多的麻煩。而更糟糕的是,很多人更高估了自己對C++的認識,貿貿然就隨隨便便造輪子,還大規模的在代碼上到處氾濫。


分享到:


相關文章: