轉自:http://www.cnblogs.com/miloyip/archive/2010/09/17/1828449.html
應否選擇C++
哪些程序適宜使用C++?
C++並不是萬能丹,我按經驗舉出一些C++的適用時機。
- C++適合構造程序中需求較穩定的部分,需求變化較大的部分可以使用腳本語言;
- 程序須儘可能發揮硬件的最高性能,且性能瓶頸在於CPU和內存;
- 程序須頻繁地與操做系統或硬件溝通;
- 程序必須使用C++框架/庫,如大部分遊戲引擎(如Unreal/Source)及中間件(如Havok/FMOD),雖然有些C++庫提供其餘語言的綁定,但一般原生的API性能最好、最新;
- 項目中某個目標平臺只提供C++編譯器的支持。
按應用領域來講,C++適用於開發服務器軟件、桌面應用、遊戲、實時系統、高性能計算、嵌入式系統等。
使用C++仍是C?
C++和C的設計哲學並不同,二者取捨不一樣,因此不一樣的程序員和軟件項目會有不一樣選擇,難以一律而論。與C++相比,C具有編譯速度快、容易學習、顯式描述程序細節、較少更新標準(後二者也可同時視爲缺點)等優勢。在語言層面上,C++包含絕大部分C語言的功能(例外之一,C++沒有C99的
變長數組VLA),且提供OOP和GP的特性。但其實用C也可實現OOP思想,亦可利用宏去實現某程度的GP,只不過C++的語法能較簡潔、自動地實現OOP/GP。C++的
RAII(resource acquisition is initialization,資源獲取就是初始化)特性比較獨特,C/C#/Java沒有相應功能。回顧歷史,Stroustrup開發的早期C++編譯器Cpre/
Cfront是把C++源代碼翻譯爲C,再用C編譯器編譯的。由此可知,C++編寫的程序,都能用等效的C程序代替,但C++在語言層面上提供了OOP/GP語法、更嚴格的類型檢查系統、大量額外的語言特性(如異常、
RTTI等),而且C++標準庫也較豐富。有時候C++的語法可以使程序更簡潔,如運算符重載、隱式轉換。但另外一方面,C語言的API一般比C++簡潔,能較容易供其餘語言程序調用。所以,一些C++庫會提供C的API封裝,同時也可供C程序調用。相反,有時候也會把C的API封裝成C++形式,以支持RAII和其餘C++庫整合等。
爲什麼C++性能可優於其餘語言?
相對運行於虛擬機語言(如C#/Java),C/C++直接以靜態形式把源程序編譯爲目標平臺的機器碼。通常而言,C/C++程序在編譯及連接時可進行的優化最豐富,啓動時的速度最快,運行時的額外內存開銷最少。而C/C++相對動態語言(如Python/Lua)也減小了運行時的動態類型檢測。此外,C/C++的運行行爲是肯定的,且不會有額外行爲(例如C#/Java必然會初始化變量),也不會有如垃圾收集(GC)而形成的不肯定性延遲,並且C/C++的數據結構在內存中的佈局也是肯定的。有時C++的一些功能會使程序性能優於C,當中之內聯和模版最爲突出,這兩項功能使C++標準庫的sort()一般比C標準庫的qsort()
快多倍(C可用宏或人手編碼去解決此問題)。另外一方面,C/C++能直接映射機器碼,之間沒有另外一層中間語言,所以能夠作底層優化,例如使用
內部(intrinsic)函數和嵌入彙編語言。然而,許多C++的性能優勢並不是免費午飯,代價包括較長的編譯連接時間和較易出錯,於是增長開發時間和成本,這點稍後補充。
我進行了一個簡單全局渲染性能測試(512x512像素,每像素10000個採樣),C++ 1小時36分、Java 3小時18分、Python約18天、Ruby約351天。評測方式和其餘語言的結果詳見
博文。
C++常見問題
C++源代碼跨平臺嗎?
C++有不錯的跨平臺能力,但因爲直接映射硬件,因性能優化的關係,跨平臺能力不及Java及多數腳本語言。然而,實踐跨平臺的C++軟件仍是可行的,但須注意如下問題:
- C++標準沒有規定原始數據類型(如int)的大小,須要特定大小的類型時,可自訂類型(如int32_t),同時對任何類型使用sizeof()而不假設其大小;
- 字節序(byte order)按CPU有所不一樣,特別要注意二進制輸入輸出、reinterpret_cast法;
- 原始數據和結構類型的地址對齊有差別;
- 編譯器提供的一些編譯器或平臺專用擴充指令;
- 避免做應用二進制接口(application binary interface, ABI)的假設,例如調用函數時參數的取值順序在C/C++中沒定義,在C++中也不可隨便假設RTTI/虛表等實現方式。
總括而言,跨平臺C++軟件可在頭文件中用宏檢測編譯器和平臺,再用宏、typedef、自定平臺相關實現等方法去實踐跨平臺,C++標準不會提供這類幫助。
C++程序容易崩潰?
和許多語言相比,C/C++提供不安全的功能以最優化性能,有可能形成崩潰。但要注意,不少運行時錯誤,如向空指針/引用解引用、數組越界、堆棧溢出等,其餘語言也會報錯或拋出異常,這些都是程序問題,而不是語言自己的問題。有些意見認爲,出現這類運行時錯誤,應該儘可能寫入日誌並當即崩潰,不應讓程序繼續運行,以避免形成更大的影響(例如程序繼續把內存中錯誤的數據覆寫文件)。若要容錯,可按業務把程序分割爲多進程,像
Chrome或使用fork()的形式。然而,C++有許多機制能夠減小錯誤,例如以
string代替C字符串;以
vector或
array(TR1)代替原始數組(有些實現可在調試模式檢測越界);使用智能指針也能減小一些原始指針的問題。另外,我最常遇到的Bug,就是沒有初始化成員變量,有時會致使崩潰,並且調試版和發行版的行爲可能不一樣。
C++要手動作內存管理?
C++同時提供在堆棧上的自動局部變量,以及從自由存儲(free store)分配的對象。對於後者,程序員需手動釋放,或使用不一樣的容器和智能指針。 C++程序員常常進一步優化內存,自定義內存分配策略以提高效能,例如使用對象池、自定義的單向/雙向堆棧區等。雖然C++0x還沒加入GC功能,但也能夠自行編寫或使用現成庫。此外,C/C++也能夠直接使用操做系統提供的內存相關功能,例如內存映射文件、共享內存等。
使用C++常要重造輪子?
我曾參與的C++項目,都會重造很多標準庫已提供的功能,此狀況在其餘語言中較少出現。我試圖分析箇中緣由。首先,C++標準庫相對不少語言來講是貧乏的,各開發者便會重複地製造自訂庫。從另外一個角度看,C++標準庫是用C++編寫的(不少其餘語言不用自身而是用C/C++去編寫庫),在能力和性能上,自訂庫和標準庫並沒有本質差異;另外,標準庫爲通用而設,對不一樣平臺及多種使用需求做取捨,性能上有所影響,例如EA公司就曾發表自制的EASTL規格,描述遊戲開發方面對STL的性能及功能需求的特色;此外,多個C++庫一塊兒使用,常常會因規範不一樣而引發衝突,又或功能重疊,因此項目可能須自行開發,或引入其餘庫的概念或實現(如
Boost/
TR1/
Loki),改寫以符合項目規範。
C++編譯速度很慢?
錯,是很是慢。我認爲C++多是實用程序語言中編譯速度最慢的。此問題涉及C++沿用C的編譯連接方式,又加入了複雜的類/泛型聲明和內聯機制,使編譯時間倍增。在C++對編譯方法改革以前(如
module提案),可以使用如下技巧改善:第一,使用
pimpl手法,因性能損耗應用於調用次數很少的類;第二,僅包含必要頭文件,並儘可能使用及提供前置聲明版本的頭文件(如iosfwd);第三採用基於接口的設計,但須注意虛函數調用成本;第四,採用
unity build,即把多個cpp文件結合在一個編譯單元進行編譯;第五,採用分佈式生成系統如
IncrediBuild。
C++缺少什麼功能?
雖然C++已經很是複雜,但仍缺乏不少常見功能。 C++0x做出了很多改善,例如語言方面加入Lambda函數、閉包、類型推導聲明等,而庫方面則加入正則表達式、採用哈希表的unordered_set/unordered_map、引用計數智能指針shared_ptr/weak_ptr等。但最值得留意的是C++0x引入多線程的語法和庫功能,這是C++演進的一大步。然而,模組、GC、反射機制等功能雖有提案,卻未加進C++0x。
C++使用建議
爲應用挑選特性集
我贊成Stroustrup關於使用C++各類技術的迴應:「你能夠作,不意味着你必須這麼作。(Just because you can do it, doesn't mean that you have to.)」 C++充滿豐富的特性,但同時帶來不一樣問題,例如過度複雜、編譯及運行性能的損耗。通常可考慮是否使用多重繼承、異常、RTTI,並調節使用模版及模版元編程的程度。使用過度複雜的設計和功能,可能會令部分團隊成員更難理解和維護。
爲團隊創建編程規範
C++的編碼自由度很高,容易編寫風格迥異的代碼,C++自己也沒有定義一些標準規範。並且,C++的源文件物理構成,較許多語言複雜。所以,除了決定特性集,每一個團隊應創建一套編程規範,包括源文件格式(可以使用文件模版)、花括號風格。
儘可能使用C++風格而非C風格
因爲C++有對C兼容的包袱,一些功能可使用C風格實現,但最好使用C++提供的新功能。最基本的是儘可能以具名常量、內聯函數和泛型取代宏,只把宏用在條件式編譯及特殊狀況。舊式的C要求局部變量聲明在做用域開端,C++則無此限制,應把變量聲明儘可能置於鄰近其使用的地方,for()的循環變量聲明可置於for的括號內。 C++中能增強類型安全的功能應儘可能使用,例如避免「萬能」指針void *,而使用個別或泛型類型;用bool而非int表示布爾值;選用4種C++ cast關鍵字代替簡單的強制轉換。
結合其餘語言
如前文所述,C++並不是適合全部應用情境,有時能夠混合其餘語言使用,包括用C++擴展其餘語言,或在C++程序中嵌入腳本語言引擎。對於後者,除了使用各類腳本語言的專門API,還可以使用
Boost或
SWIG做整合。
C++學習建議
C++缺點之一,是相對許多語言複雜,並且難學難精。許多人說學習C語言只需一本K&R
《C程序設計語言》便可,但C++書籍倒是多不勝數。我是從C進入C++,皆是靠閱讀自學。在此分享一點學習心得。我的認爲,學習C++可分爲4個層次:
因爲我主要是應用C++,大約只停留於第2、三個層次。然而,C++只是軟件開發的一環而已,單憑語言並不能應付業務和工程上的問題。建議讀者不要強求幾年內「完全學會C++的知識」,到達第二層左右便從工做實戰中汲取經驗,有興趣才慢慢繼續學習更高層次的知識。雖然學習C++有難度,但也是至關有趣且有知足感的。
數十年來,C++雖有起伏,但她依靠其使用者而不斷獲得頑強的生命力,相信在我退休以前都不會與她分離,也但願更進一步瞭解她,與她走進將來。