如何寫優美的c++代碼?

怎麼寫出地道和好的c++代碼,而不像c語言或其他語言?


Follow good examples.

找出你認為「優美」的 C++ 項目,閱讀其 coding standards,然後照著做。


優美這個詞太抽象,不如換一種說法,什麼叫好的C++代碼?雖然很多語言對好代碼的標準基本一致,比方說簡潔、簡單、功能單一、靈活;不搞副作用,不要裝神弄鬼,避免繁文縟節,但是,C++對好代碼的標準自有其獨到之處,當然,以上標準是必須過關的,但是,更有兩條更重要的優先原則,那就是零懲罰和類型安全。在此,重點強調零懲罰,不為不需要的功能付出任何代價,哪怕是一點點。任何違背這條原則的代碼,不管寫得多好,不管出自誰之手,最後必將被狠狠打臉。

比方說,stl裡面的string,搞什麼短字元串優化,就違背了零懲罰。這個優化,對於短字元串自然很能提高性能,但是帶來的代價:1、string實例的內存佔用變大了,那怕長字元串不必用到本地緩衝,也要背負這一塊用於優化短字元串的內存;2、每一次對字元串的訪問,必先判斷其大小後才確定字元串緩衝的位置,在本地呢還是在遙遠的堆裡面,這就付出了cpu代價。實際上,短字元串優化的問題是由於對內存分配的更高要求造成的,這裡面要攻克的是allocator,而非在字元串上大做文章。

又好比說,stl的list實現,對於元素的刪除,還要到list中查找到其相應的迭代器,然後通過迭代器來erase元素,這就是O(N)的複雜度,這就又不零懲罰了,無論如何,list必須提供這樣的介面,可以在必要時候,通過元素本身,就能O(1)的效率來刪除元素。

還有vector,為了照顧一小簇不能輕易複製的怪異類型(虛繼承、或者其內部欄位又引用到自己),每一次vector要擴展容量時候(或者要素交換位置),不能隨意將原有的緩衝整個複製過來,必須不厭其煩的一一調用每個元素的移動複製構造函數(c++11之前,還是複製構造函數,這損耗就更大了),然後再一一調用舊緩衝元素的析構函數。vector擴容時,只需做簡單緩衝內存複製操作,然後再free舊緩衝的內存,就行了,不必要再做什麼元素的構造函數或者析構函數的操作了,因為大多數的類型,其實就是這麼簡單,現在因為怪異類型的存在,就要承擔這不必要的代價。所以,現有stl的vector實現也不零懲罰,所以當然不優美了。那麼,對於怪異類型的元素怎麼辦,很簡單,要麼就用list來儲存,要麼就用指針vector。而且,代碼中出現怪異類型,多數情況下,意味著要重構。怪異類型就是內存布局複雜,這就不簡單了。

零懲罰意味著輕量級,意味著儘可能保持代碼模塊的獨立性,意味著類型之間的耦合達到最小,意味著副作用降到最低,而且,多數情況下,做到零懲罰了,其他的什麼代碼簡潔、易測試、高性能自然而然也就實現了。當然,堅持零懲罰的確不容易,必須經過大量的練習,時刻清楚代碼在做什麼,要實現什麼功能,避免複雜的對象內存布局,複雜的代碼邏輯。

題外話,C++開發效率慢,寫代碼難,總結起來,不過這三個問題:

1、高效靈活簡單的內存管理方式(stl的allocator遠遠無法滿足需求)和對象生命周期管理;

2、反射,運行時豐富的類型信息,反射遠比想像中的重要,面向對象編程裡頭更少不了反射,反射可以將更多的代碼實現變成數據,然後以解釋器的方式來推動代碼,將表驅動的精神發揚光大。表面沒有反射,內部實現充滿了反射,企圖避開反射最後的結果就是大屎山堆的垃圾代碼,stl裡面不知存在多少這樣的垃圾,本座對stl的不滿,可以說三天三夜也說不完,種種不滿意。另外,反射可以大大緩解漫長編譯的痛苦;

3、打通編譯期和運行期的信息隔閡,編譯期豐富的信息類型進不了運行時,以致運行時不能充分發揮編譯器的諸多功能以及類型安全。搬掉這三座大山,用C++寫代碼,真是爽到了極點,高開發效率,高運行效率,而且代碼又可以很簡潔。


感謝邀請,作為一個scala程序員我已經很多年沒有提交過像樣的c++代碼了。

我覺得像c++或者scala這樣的語言,對於優美,是沒有大一統的標準的。如果參加一個有很多人參加的項目,我覺得你要在你的項目里找所謂的「標準」。如果你自己一個人的項目,推薦看google的c++代碼標準,風格比較簡單實用,但也不是每個人都喜歡。

我記得我第一次參加一個c++的項目的時候,我開始三個月都是不太提交代碼的,我就跟著看,看人家怎麼寫,什麼風格。這玩意不是java,不同項目風格真是很迥異的。拿我以前那一套過來,這可能會讓會讓新同事們不適或者反感。

比如說functor的名字是大寫還是小寫?比如說左括弧後面要不要空一格?比如什麼時候使用繼承?這個不同項目不一樣,咱們得遵循已經存在的規則。


寫程序你一定要記住一點,程序是寫給人看的!

所以,注釋要清楚,變數命名要有意義,代碼邏輯要清楚,介面清晰明確。然後代碼自然就好看了。


C++離優美這個詞比較遠,因為本來就號稱是適合工作的工具語言,瑞士軍刀,萬能鑰匙。優美的計算機語言起碼是那些適合教學的,有些語言誕生之初就比較在意優美,比如Python,雖然強制空格可能會被很多人詬病,但是這也是為了優美啊,早期比較優美的語言可能是Pascal,或者後來的Delphi也還算比較優美,算了,再說下去該引起語言的論戰了。


C++ Core Guidelines


不要掛羊頭賣狗肉,做什麼事就取什麼名字


推薦閱讀:

為什麼C/C++相同內存布局的struct不能互相cast?
程序員應該將精力放在研究編程語言本身還是用編程語言創造好的軟體?
Google對C++的影響有多大?
為什麼 C 語言源程序最後一行要是一個空行?
如何以最小的改動盡量不改變已有代碼的情況下適應不斷變更的需求?

TAG:編程 | 代碼質量 | CC |