




已閱讀5頁(yè),還剩58頁(yè)未讀, 繼續(xù)免費(fèi)閱讀
版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
Google C+編程規(guī)范 背景Google的開(kāi)源項(xiàng)目大多使用C+開(kāi)發(fā)。每一個(gè)C+程序員也都知道,C+具有很多強(qiáng)大的語(yǔ)言特性,但這種強(qiáng)大不可避免的導(dǎo)致它的復(fù)雜,這種復(fù)雜會(huì)使得代碼更易于出現(xiàn)bug、難于閱讀和維護(hù)。本指南的目的是通過(guò)詳細(xì)闡述在C+編碼時(shí)要怎樣寫(xiě)、不要怎樣寫(xiě)來(lái)規(guī)避其復(fù)雜性。這些規(guī)則可在允許代碼有效使用C+語(yǔ)言特性的同時(shí)使其易于管理。風(fēng)格,也被視為可讀性,主要指稱管理C+代碼的習(xí)慣。使用術(shù)語(yǔ)風(fēng)格有點(diǎn)用詞不當(dāng),因?yàn)檫@些習(xí)慣遠(yuǎn)不止源代碼文件格式這么簡(jiǎn)單。使代碼易于管理的方法之一是增強(qiáng)代碼一致性,讓別人可以讀懂你的代碼是很重要的,保持統(tǒng)一編程風(fēng)格意味著可以輕松根據(jù)“模式匹配”規(guī)則推斷各種符號(hào)的含義。創(chuàng)建通用的、必需的習(xí)慣用語(yǔ)和模式可以使代碼更加容易理解,在某些情況下改變一些編程風(fēng)格可能會(huì)是好的選擇,但我們還是應(yīng)該遵循一致性原則,盡量不這樣去做。本指南的另一個(gè)觀點(diǎn)是C+特性的臃腫。C+是一門(mén)包含大量高級(jí)特性的巨型語(yǔ)言,某些情況下,我們會(huì)限制甚至禁止使用某些特性使代碼簡(jiǎn)化,避免可能導(dǎo)致的各種問(wèn)題,指南中列舉了這類特性,并解釋說(shuō)為什么這些特性是被限制使用的。由Google開(kāi)發(fā)的開(kāi)源項(xiàng)目將遵照本指南約定。注意:本指南并非C+教程,我們假定讀者已經(jīng)對(duì)C+非常熟悉。 頭文件通常,每一個(gè).cc文件(C+的源文件)都有一個(gè)對(duì)應(yīng)的.h文件(頭文件),也有一些例外,如單元測(cè)試代碼和只包含main()的.cc文件。正確使用頭文件可令代碼在可讀性、文件大小和性能上大為改觀。下面的規(guī)則將引導(dǎo)你規(guī)避使用頭文件時(shí)的各種麻煩。1. #define的保護(hù)所有頭文件都應(yīng)該使用#define防止頭文件被多重包含(multiple inclusion),命名格式當(dāng)是:_H_為保證唯一性,頭文件的命名應(yīng)基于其所在項(xiàng)目源代碼樹(shù)的全路徑。例如,項(xiàng)目foo中的頭文件foo/src/bar/baz.h按如下方式保護(hù):#ifndef FOO_BAR_BAZ_H_#define FOO_BAR_BAZ_H_.#endif / FOO_BAR_BAZ_H_2. 頭文件依賴使用前置聲明(forward declarations)盡量減少.h文件中#include的數(shù)量。當(dāng)一個(gè)頭文件被包含的同時(shí)也引入了一項(xiàng)新的依賴(dependency),只要該頭文件被修改,代碼就要重新編譯。如果你的頭文件包含了其他頭文件,這些頭文件的任何改變也將導(dǎo)致那些包含了你的頭文件的代碼重新編譯。因此,我們寧可盡量少包含頭文件,尤其是那些包含在其他頭文件中的。使用前置聲明可以顯著減少需要包含的頭文件數(shù)量。舉例說(shuō)明:頭文件中用到類File,但不需要訪問(wèn)File的聲明,則頭文件中只需前置聲明class File;無(wú)需#include file/base/file.h。在頭文件如何做到使用類Foo而無(wú)需訪問(wèn)類的定義?1) 將數(shù)據(jù)成員類型聲明為Foo *或Foo &;2) 參數(shù)、返回值類型為Foo的函數(shù)只是聲明(但不定義實(shí)現(xiàn));3) 靜態(tài)數(shù)據(jù)成員的類型可以被聲明為Foo,因?yàn)殪o態(tài)數(shù)據(jù)成員的定義在類定義之外。另一方面,如果你的類是Foo的子類,或者含有類型為Foo的非靜態(tài)數(shù)據(jù)成員,則必須為之包含頭文件。有時(shí),使用指針成員(pointer members,如果是scoped_ptr更好)替代對(duì)象成員(object members)的確更有意義。然而,這樣的做法會(huì)降低代碼可讀性及執(zhí)行效率。如果僅僅為了少包含頭文件,還是不要這樣替代的好。當(dāng)然,.cc文件無(wú)論如何都需要所使用類的定義部分,自然也就會(huì)包含若干頭文件。譯者注:能依賴聲明的就不要依賴定義。3. 內(nèi)聯(lián)函數(shù)只有當(dāng)函數(shù)只有10行甚至更少時(shí)才會(huì)將其定義為內(nèi)聯(lián)函數(shù)(inline function)。定義(Definition):當(dāng)函數(shù)被聲明為內(nèi)聯(lián)函數(shù)之后,編譯器可能會(huì)將其內(nèi)聯(lián)展開(kāi),無(wú)需按通常的函數(shù)調(diào)用機(jī)制調(diào)用內(nèi)聯(lián)函數(shù)。優(yōu)點(diǎn):當(dāng)函數(shù)體比較小的時(shí)候,內(nèi)聯(lián)該函數(shù)可以令目標(biāo)代碼更加高效。對(duì)于存取函數(shù)(accessor、mutator)以及其他一些比較短的關(guān)鍵執(zhí)行函數(shù)。缺點(diǎn):濫用內(nèi)聯(lián)將導(dǎo)致程序變慢,內(nèi)聯(lián)有可能是目標(biāo)代碼量或增或減,這取決于被內(nèi)聯(lián)的函數(shù)的大小。內(nèi)聯(lián)較短小的存取函數(shù)通常會(huì)減少代碼量,但內(nèi)聯(lián)一個(gè)很大的函數(shù)(譯者注:如果編譯器允許的話)將戲劇性的增加代碼量。在現(xiàn)代處理器上,由于更好的利用指令緩存(instruction cache),小巧的代碼往往執(zhí)行更快。結(jié)論:一個(gè)比較得當(dāng)?shù)奶幚硪?guī)則是,不要內(nèi)聯(lián)超過(guò)10行的函數(shù)。對(duì)于析構(gòu)函數(shù)應(yīng)慎重對(duì)待,析構(gòu)函數(shù)往往比其表面看起來(lái)要長(zhǎng),因?yàn)橛幸恍╇[式成員和基類析構(gòu)函數(shù)(如果有的話)被調(diào)用!另一有用的處理規(guī)則:內(nèi)聯(lián)那些包含循環(huán)或switch語(yǔ)句的函數(shù)是得不償失的,除非在大多數(shù)情況下,這些循環(huán)或switch語(yǔ)句從不執(zhí)行。重要的是,虛函數(shù)和遞歸函數(shù)即使被聲明為內(nèi)聯(lián)的也不一定就是內(nèi)聯(lián)函數(shù)。通常,遞歸函數(shù)不應(yīng)該被聲明為內(nèi)聯(lián)的(譯者注:遞歸調(diào)用堆棧的展開(kāi)并不像循環(huán)那么簡(jiǎn)單,比如遞歸層數(shù)在編譯時(shí)可能是未知的,大多數(shù)編譯器都不支持內(nèi)聯(lián)遞歸函數(shù))。析構(gòu)函數(shù)內(nèi)聯(lián)的主要原因是其定義在類的定義中,為了方便抑或是對(duì)其行為給出文檔。4. -inl.h文件復(fù)雜的內(nèi)聯(lián)函數(shù)的定義,應(yīng)放在后綴名為-inl.h的頭文件中。在頭文件中給出內(nèi)聯(lián)函數(shù)的定義,可令編譯器將其在調(diào)用處內(nèi)聯(lián)展開(kāi)。然而,實(shí)現(xiàn)代碼應(yīng)完全放到.cc文件中,我們不希望.h文件中出現(xiàn)太多實(shí)現(xiàn)代碼,除非這樣做在可讀性和效率上有明顯優(yōu)勢(shì)。如果內(nèi)聯(lián)函數(shù)的定義比較短小、邏輯比較簡(jiǎn)單,其實(shí)現(xiàn)代碼可以放在.h文件中。例如,存取函數(shù)的實(shí)現(xiàn)理所當(dāng)然都放在類定義中。出于實(shí)現(xiàn)和調(diào)用的方便,較復(fù)雜的內(nèi)聯(lián)函數(shù)也可以放到.h文件中,如果你覺(jué)得這樣會(huì)使頭文件顯得笨重,還可以將其分離到單獨(dú)的-inl.h中。這樣即把實(shí)現(xiàn)和類定義分離開(kāi)來(lái),當(dāng)需要時(shí)包含實(shí)現(xiàn)所在的-inl.h即可。-inl.h文件還可用于函數(shù)模板的定義,從而使得模板定義可讀性增強(qiáng)。要提醒的一點(diǎn)是,-inl.h和其他頭文件一樣,也需要#define保護(hù)。5. 函數(shù)參數(shù)順序(Function Parameter Ordering)定義函數(shù)時(shí),參數(shù)順序?yàn)椋狠斎雲(yún)?shù)在前,輸出參數(shù)在后。C/C+函數(shù)參數(shù)分為輸入?yún)?shù)和輸出參數(shù)兩種,有時(shí)輸入?yún)?shù)也會(huì)輸出(譯者注:值被修改時(shí))。輸入?yún)?shù)一般傳值或常數(shù)引用(const references),輸出參數(shù)或輸入/輸出參數(shù)為非常數(shù)指針(non-const pointers)。對(duì)參數(shù)排序時(shí),將所有輸入?yún)?shù)置于輸出參數(shù)之前。不要僅僅因?yàn)槭切绿砑拥膮?shù),就將其置于最后,而應(yīng)該依然置于輸出參數(shù)之前。這一點(diǎn)并不是必須遵循的規(guī)則,輸入/輸出兩用參數(shù)(通常是類/結(jié)構(gòu)體變量)混在其中,會(huì)使得規(guī)則難以遵循。6. 包含文件的名稱及次序?qū)涡驑?biāo)準(zhǔn)化可增強(qiáng)可讀性、避免隱藏依賴(hidden dependencies,譯者注:隱藏依賴主要是指包含的文件中編譯時(shí)),次序如下:C庫(kù)、C+庫(kù)、其他庫(kù)的.h、項(xiàng)目?jī)?nèi)的.h。項(xiàng)目?jī)?nèi)頭文件應(yīng)按照項(xiàng)目源代碼目錄樹(shù)結(jié)構(gòu)排列,并且避免使用UNIX文件路徑.(當(dāng)前目錄)和.(父目錄)。例如,google-awesome-project/src/base/logging.h應(yīng)像這樣被包含:#include base/logging.hdir/foo.cc的主要作用是執(zhí)行或測(cè)試dir2/foo2.h的功能,foo.cc中包含頭文件的次序如下: dir2/foo2.h(優(yōu)先位置,詳情如下) C系統(tǒng)文件 C+系統(tǒng)文件 其他庫(kù)頭文件 本項(xiàng)目?jī)?nèi)頭文件這種排序方式可有效減少隱藏依賴,我們希望每一個(gè)頭文件獨(dú)立編譯。最簡(jiǎn)單的實(shí)現(xiàn)方式是將其作為第一個(gè).h文件包含在對(duì)應(yīng)的.cc中。dir/foo.cc和dir2/foo2.h通常位于相同目錄下(像base/basictypes_unittest.cc和base/basictypes.h),但也可在不同目錄下。相同目錄下頭文件按字母序是不錯(cuò)的選擇。舉例來(lái)說(shuō),google-awesome-project/src/foo/internal/fooserver.cc的包含次序如下:#include foo/public/fooserver.h / 優(yōu)先位置#include #include #include #include #include base/basictypes.h#include base/commandlineflags.h#include foo/public/bar.h_譯者:英語(yǔ)不太好,翻譯的也就不太好。這一篇主要提到的是頭文件的一些規(guī)則,總結(jié)一下:1. 避免多重包含是學(xué)編程時(shí)最基本的要求;2. 前置聲明是為了降低編譯依賴,防止修改一個(gè)頭文件引發(fā)多米諾效應(yīng);3. 內(nèi)聯(lián)函數(shù)的合理使用可提高代碼執(zhí)行效率;4. -inl.h可提高代碼可讀性(一般用不到吧:D);5. 標(biāo)準(zhǔn)化函數(shù)參數(shù)順序可以提高可讀性和易維護(hù)性(對(duì)函數(shù)參數(shù)的堆??臻g有輕微影響,我以前大多是相同類型放在一起);6. 包含文件的名稱使用.和.雖然方便卻易混亂,使用比較完整的項(xiàng)目路徑看上去很清晰、很條理,包含文件的次序除了美觀之外,最重要的是可以減少隱藏依賴,使每個(gè)頭文件在“最需要編譯”(對(duì)應(yīng)源文件處:D)的地方編譯,有人提出庫(kù)文件放在最后,這樣出錯(cuò)先是項(xiàng)目?jī)?nèi)的文件,頭文件都放在對(duì)應(yīng)源文件的最前面,這一點(diǎn)足以保證內(nèi)部錯(cuò)誤的及時(shí)發(fā)現(xiàn)了。 作用域1. 命名空間(Namespaces)在.cc文件中,提倡使用不具名的命名空間(unnamed namespaces,譯者注:不具名的命名空間就像不具名的類一樣,似乎被介紹的很少:-()。使用具名命名空間時(shí),其名稱可基于項(xiàng)目或路徑名稱,不要使用using指示符。定義:命名空間將全局作用域細(xì)分為不同的、具名的作用域,可有效防止全局作用域的命名沖突。優(yōu)點(diǎn):命名空間提供了(可嵌套)命名軸線(name axis,譯者注:將命名分割在不同命名空間內(nèi)),當(dāng)然,類也提供了(可嵌套)的命名軸線(譯者注:將命名分割在不同類的作用域內(nèi))。舉例來(lái)說(shuō),兩個(gè)不同項(xiàng)目的全局作用域都有一個(gè)類Foo,這樣在編譯或運(yùn)行時(shí)造成沖突。如果每個(gè)項(xiàng)目將代碼置于不同命名空間中,project1:Foo和project2:Foo作為不同符號(hào)自然不會(huì)沖突。缺點(diǎn):命名空間具有迷惑性,因?yàn)樗鼈兒皖愐粯犹峁┝祟~外的(可嵌套的)命名軸線。在頭文件中使用不具名的空間容易違背C+的唯一定義原則(One Definition Rule (ODR))。結(jié)論:根據(jù)下文將要提到的策略合理使用命名空間。1) 不具名命名空間(Unnamed Namespaces)在.cc文件中,允許甚至提倡使用不具名命名空間,以避免運(yùn)行時(shí)的命名沖突:namespace / .cc 文件中/ 命名空間的內(nèi)容無(wú)需縮進(jìn)enum UNUSED, EOF, ERROR ; / 經(jīng)常使用的符號(hào)bool AtEof() return pos_ = EOF; / 使用本命名空間內(nèi)的符號(hào)EOF / namespace然而,與特定類關(guān)聯(lián)的文件作用域聲明在該類中被聲明為類型、靜態(tài)數(shù)據(jù)成員或靜態(tài)成員函數(shù),而不是不具名命名空間的成員。像上文展示的那樣,不具名命名空間結(jié)束時(shí)用注釋/ namespace標(biāo)識(shí)。不能在.h文件中使用不具名命名空間。2) 具名命名空間(Named Namespaces)具名命名空間使用方式如下:命名空間將除文件包含、全局標(biāo)識(shí)的聲明/定義以及類的前置聲明外的整個(gè)源文件封裝起來(lái),以同其他命名空間相區(qū)分。/ .h文件namespace mynamespace / 所有聲明都置于命名空間中/ 注意不要使用縮進(jìn)class MyClass public: . void Foo(); / namespace mynamespace/ .cc文件namespace mynamespace / 函數(shù)定義都置于命名空間中void MyClass:Foo() . / namespace mynamespace通常的.cc文件會(huì)包含更多、更復(fù)雜的細(xì)節(jié),包括對(duì)其他命名空間中類的引用等。#include a.hDEFINE_bool(someflag, false, dummy flag);class C; / 全局命名空間中類C的前置聲明namespace a class A; / 命名空間a中的類a:A的前置聲明namespace b .code for b. / b中的代碼 / namespace b不要聲明命名空間std下的任何內(nèi)容,包括標(biāo)準(zhǔn)庫(kù)類的前置聲明。聲明std下的實(shí)體會(huì)導(dǎo)致不明確的行為,如,不可移植。聲明標(biāo)準(zhǔn)庫(kù)下的實(shí)體,需要包含對(duì)應(yīng)的頭文件。最好不要使用using指示符,以保證命名空間下的所有名稱都可以正常使用。/ 禁止污染命名空間using namespace foo;在.cc文件、.h文件的函數(shù)、方法或類中,可以使用using。/ 允許:.cc文件中/ .h文件中,必須在函數(shù)、方法或類的內(nèi)部使用using :foo:bar;在.cc文件、.h文件的函數(shù)、方法或類中,還可以使用命名空間別名。/ 允許:.cc文件中/ .h文件中,必須在函數(shù)、方法或類的內(nèi)部使用namespace fbz = :foo:bar:baz;2. 嵌套類(Nested Class)當(dāng)公開(kāi)嵌套類作為接口的一部分時(shí),雖然可以直接將他們保持在全局作用域中,但將嵌套類的聲明置于命名空間中是更好的選擇。定義:可以在一個(gè)類中定義另一個(gè)類,嵌套類也稱成員類(member class)。class Foo private: / Bar是嵌套在Foo中的成員類 class Bar . ;優(yōu)點(diǎn):當(dāng)嵌套(成員)類只在被嵌套類(enclosing class)中使用時(shí)很有用,將其置于被嵌套類作用域作為被嵌套類的成員不會(huì)污染其他作用域同名類。可在被嵌套類中前置聲明嵌套類,在.cc文件中定義嵌套類,避免在被嵌套類中包含嵌套類的定義,因?yàn)榍短最惖亩x通常只與實(shí)現(xiàn)相關(guān)。缺點(diǎn):只能在被嵌套類的定義中才能前置聲明嵌套類。因此,任何使用Foo:Bar*指針的頭文件必須包含整個(gè)Foo的聲明。結(jié)論:不要將嵌套類定義為public,除非它們是接口的一部分,比如,某個(gè)方法使用了這個(gè)類的一系列選項(xiàng)。3. 非成員函數(shù)(Nonmember)、靜態(tài)成員函數(shù)(Static Member)和全局函數(shù)(Global Functions)使用命名空間中的非成員函數(shù)或靜態(tài)成員函數(shù),盡量不要使用全局函數(shù)。優(yōu)點(diǎn):某些情況下,非成員函數(shù)和靜態(tài)成員函數(shù)是非常有用的,將非成員函數(shù)置于命名空間中可避免對(duì)全局作用域的污染。缺點(diǎn):將非成員函數(shù)和靜態(tài)成員函數(shù)作為新類的成員或許更有意義,當(dāng)它們需要訪問(wèn)外部資源或具有重要依賴時(shí)更是如此。結(jié)論:有時(shí),不把函數(shù)限定在類的實(shí)體中是有益的,甚至需要這么做,要么作為靜態(tài)成員,要么作為非成員函數(shù)。非成員函數(shù)不應(yīng)依賴于外部變量,并盡量置于某個(gè)命名空間中。相比單純?yōu)榱朔庋b若干不共享任何靜態(tài)數(shù)據(jù)的靜態(tài)成員函數(shù)而創(chuàng)建類,不如使用命名空間。定義于同一編譯單元的函數(shù),被其他編譯單元直接調(diào)用可能會(huì)引入不必要的耦合和連接依賴;靜態(tài)成員函數(shù)對(duì)此尤其敏感??梢钥紤]提取到新類中,或者將函數(shù)置于獨(dú)立庫(kù)的命名空間中。如果你確實(shí)需要定義非成員函數(shù),又只是在.cc文件中使用它,可使用不具名命名空間或static關(guān)聯(lián)(如static int Foo() .)限定其作用域。4. 局部變量(Local Variables)將函數(shù)變量盡可能置于最小作用域內(nèi),在聲明變量時(shí)將其初始化。C+允許在函數(shù)的任何位置聲明變量。我們提倡在盡可能小的作用域中聲明變量,離第一次使用越近越好。這使得代碼易于閱讀,易于定位變量的聲明位置、變量類型和初始值。特別是,應(yīng)使用初始化代替聲明+賦值的方式。int i;i = f(); / 壞初始化和聲明分離nt j = g(); / 好初始化時(shí)聲明注意:gcc可正確執(zhí)行for (int i = 0; i 10; +i)(i的作用域僅限for循環(huán)),因此其他for循環(huán)中可重用i。if和while等語(yǔ)句中,作用域聲明(scope declaration)同樣是正確的。while (const char* p = strchr(str, /) str = p + 1;注意:如果變量是一個(gè)對(duì)象,每次進(jìn)入作用域都要調(diào)用其構(gòu)造函數(shù),每次退出作用域都要調(diào)用其析構(gòu)函數(shù)。/ 低效的實(shí)現(xiàn)for (int i = 0; i 1000000; +i) Foo f; / 構(gòu)造函數(shù)和析構(gòu)函數(shù)分別調(diào)用1000000次! f.DoSomething(i);類似變量放到循環(huán)作用域外面聲明要高效的多:Foo f; / 構(gòu)造函數(shù)和析構(gòu)函數(shù)只調(diào)用1次for (int i = 0; i 1000000; +i) f.DoSomething(i);5. 全局變量(Global Variables)class類型的全局變量是被禁止的,內(nèi)建類型的全局變量是允許的,當(dāng)然多線程代碼中非常數(shù)全局變量也是被禁止的。永遠(yuǎn)不要使用函數(shù)返回值初始化全局變量。不幸的是,全局變量的構(gòu)造函數(shù)、析構(gòu)函數(shù)以及初始化操作的調(diào)用順序只是被部分規(guī)定,每次生成有可能會(huì)有變化,從而導(dǎo)致難以發(fā)現(xiàn)的bugs。因此,禁止使用class類型的全局變量(包括STL的string, vector等等),因?yàn)樗鼈兊某跏蓟樞蛴锌赡軐?dǎo)致構(gòu)造出現(xiàn)問(wèn)題。內(nèi)建類型和由內(nèi)建類型構(gòu)成的沒(méi)有構(gòu)造函數(shù)的結(jié)構(gòu)體可以使用,如果你一定要使用class類型的全局變量,請(qǐng)使用單件模式(singleton pattern)。對(duì)于全局的字符串常量,使用C風(fēng)格的字符串,而不要使用STL的字符串:const char kFrogSays = ribbet;雖然允許在全局作用域中使用全局變量,使用時(shí)務(wù)必三思。大多數(shù)全局變量應(yīng)該是類的靜態(tài)數(shù)據(jù)成員,或者當(dāng)其只在.cc文件中使用時(shí),將其定義到不具名命名空間中,或者使用靜態(tài)關(guān)聯(lián)以限制變量的作用域。記住,靜態(tài)成員變量視作全局變量,所以,也不能是class類型!_譯者:這一篇主要提到的是作用域的一些規(guī)則,總結(jié)一下:1. .cc中的不具名命名空間可避免命名沖突、限定作用域,避免直接使用using提示符污染命名空間;2. 嵌套類符合局部使用原則,只是不能在其他頭文件中前置聲明,盡量不要public;3. 盡量不用全局函數(shù)和全局變量,考慮作用域和命名空間限制,盡量單獨(dú)形成編譯單元;4. 多線程中的全局變量(含靜態(tài)成員變量)不要使用class類型(含STL容器),避免不明確行為導(dǎo)致的bugs。作用域的使用,除了考慮名稱污染、可讀性之外,主要是為降低耦合度,提高編譯、執(zhí)行效率。 類類是C+中基本的代碼單元,自然被廣泛使用。本節(jié)列舉了在寫(xiě)一個(gè)類時(shí)要做什么、不要做什么。1. 構(gòu)造函數(shù)(Constructor)的職責(zé)構(gòu)造函數(shù)中只進(jìn)行那些沒(méi)有實(shí)際意義的(trivial,譯者注:簡(jiǎn)單初始化對(duì)于程序執(zhí)行沒(méi)有實(shí)際的邏輯意義,因?yàn)槌蓡T變量的“有意義”的值大多不在構(gòu)造函數(shù)中確定)初始化,可能的話,使用Init()方法集中初始化為有意義的(non-trivial)數(shù)據(jù)。定義:在構(gòu)造函數(shù)中執(zhí)行初始化操作。優(yōu)點(diǎn):排版方便,無(wú)需擔(dān)心類是否初始化。缺點(diǎn):在構(gòu)造函數(shù)中執(zhí)行操作引起的問(wèn)題有:1) 構(gòu)造函數(shù)中不易報(bào)告錯(cuò)誤,不能使用異常。2) 操作失敗會(huì)造成對(duì)象初始化失敗,引起不確定狀態(tài)。3) 構(gòu)造函數(shù)內(nèi)調(diào)用虛函數(shù),調(diào)用不會(huì)派發(fā)到子類實(shí)現(xiàn)中,即使當(dāng)前沒(méi)有子類化實(shí)現(xiàn),將來(lái)仍是隱患。4) 如果有人創(chuàng)建該類型的全局變量(雖然違背了上節(jié)提到的規(guī)則),構(gòu)造函數(shù)將在main()之前被調(diào)用,有可能破壞構(gòu)造函數(shù)中暗含的假設(shè)條件。例如,gflags尚未初始化。結(jié)論:如果對(duì)象需要有意義的(non-trivial)初始化,考慮使用另外的Init()方法并(或)增加一個(gè)成員標(biāo)記用于指示對(duì)象是否已經(jīng)初始化成功。2. 默認(rèn)構(gòu)造函數(shù)(Default Constructors)如果一個(gè)類定義了若干成員變量又沒(méi)有其他構(gòu)造函數(shù),需要定義一個(gè)默認(rèn)構(gòu)造函數(shù),否則編譯器將自動(dòng)生產(chǎn)默認(rèn)構(gòu)造函數(shù)。定義:新建一個(gè)沒(méi)有參數(shù)的對(duì)象時(shí),默認(rèn)構(gòu)造函數(shù)被調(diào)用,當(dāng)調(diào)用new(為數(shù)組)時(shí),默認(rèn)構(gòu)造函數(shù)總是被調(diào)用。優(yōu)點(diǎn):默認(rèn)將結(jié)構(gòu)體初始化為“不可能的”值,使調(diào)試更加容易。缺點(diǎn):對(duì)代碼編寫(xiě)者來(lái)說(shuō),這是多余的工作。結(jié)論:如果類中定義了成員變量,沒(méi)有提供其他構(gòu)造函數(shù),你需要定義一個(gè)默認(rèn)構(gòu)造函數(shù)(沒(méi)有參數(shù))。默認(rèn)構(gòu)造函數(shù)更適合于初始化對(duì)象,使對(duì)象內(nèi)部狀態(tài)(internal state)一致、有效。提供默認(rèn)構(gòu)造函數(shù)的原因是:如果你沒(méi)有提供其他構(gòu)造函數(shù),又沒(méi)有定義默認(rèn)構(gòu)造函數(shù),編譯器將為你自動(dòng)生成一個(gè),編譯器生成的構(gòu)造函數(shù)并不會(huì)對(duì)對(duì)象進(jìn)行初始化。如果你定義的類繼承現(xiàn)有類,而你又沒(méi)有增加新的成員變量,則不需要為新類定義默認(rèn)構(gòu)造函數(shù)。3. 明確的構(gòu)造函數(shù)(Explicit Constructors)對(duì)單參數(shù)構(gòu)造函數(shù)使用C+關(guān)鍵字explicit。定義:通常,只有一個(gè)參數(shù)的構(gòu)造函數(shù)可被用于轉(zhuǎn)換(conversion,譯者注:主要指隱式轉(zhuǎn)換,下文可見(jiàn)),例如,定義了Foo:Foo(string name),當(dāng)向需要傳入一個(gè)Foo對(duì)象的函數(shù)傳入一個(gè)字符串時(shí),構(gòu)造函數(shù)Foo:Foo(string name)被調(diào)用并將該字符串轉(zhuǎn)換為一個(gè)Foo臨時(shí)對(duì)象傳給調(diào)用函數(shù)??瓷先ズ芊奖?,但如果你并不希望如此通過(guò)轉(zhuǎn)換生成一個(gè)新對(duì)象的話,麻煩也隨之而來(lái)。為避免構(gòu)造函數(shù)被調(diào)用造成隱式轉(zhuǎn)換,可以將其聲明為explicit。優(yōu)點(diǎn):避免不合時(shí)宜的變換。缺點(diǎn):無(wú)。結(jié)論:所有單參數(shù)構(gòu)造函數(shù)必須是明確的。在類定義中,將關(guān)鍵字explicit加到單參數(shù)構(gòu)造函數(shù)前:explicit Foo(string name);例外:在少數(shù)情況下,拷貝構(gòu)造函數(shù)可以不聲明為explicit;特意作為其他類的透明包裝器的類。類似例外情況應(yīng)在注釋中明確說(shuō)明。4. 拷貝構(gòu)造函數(shù)(Copy Constructors)僅在代碼中需要拷貝一個(gè)類對(duì)象的時(shí)候使用拷貝構(gòu)造函數(shù);不需要拷貝時(shí)應(yīng)使用DISALLOW_COPY_AND_ASSIGN。定義:通過(guò)拷貝新建對(duì)象時(shí)可使用拷貝構(gòu)造函數(shù)(特別是對(duì)象的傳值時(shí))。優(yōu)點(diǎn):拷貝構(gòu)造函數(shù)使得拷貝對(duì)象更加容易,STL容器要求所有內(nèi)容可拷貝、可賦值。缺點(diǎn):C+中對(duì)象的隱式拷貝是導(dǎo)致很多性能問(wèn)題和bugs的根源??截悩?gòu)造函數(shù)降低了代碼可讀性,相比按引用傳遞,跟蹤按值傳遞的對(duì)象更加困難,對(duì)象修改的地方變得難以捉摸。結(jié)論:大量的類并不需要可拷貝,也不需要一個(gè)拷貝構(gòu)造函數(shù)或賦值操作(assignment operator)。不幸的是,如果你不主動(dòng)聲明它們,編譯器會(huì)為你自動(dòng)生成,而且是public的??梢钥紤]在類的private中添加空的(dummy)拷貝構(gòu)造函數(shù)和賦值操作,只有聲明,沒(méi)有定義。由于這些空程序聲明為private,當(dāng)其他代碼試圖使用它們的時(shí)候,編譯器將報(bào)錯(cuò)。為了方便,可以使用宏DISALLOW_COPY_AND_ASSIGN:/ 禁止使用拷貝構(gòu)造函數(shù)和賦值操作的宏/ 應(yīng)在類的private:中使用#define DISALLOW_COPY_AND_ASSIGN(TypeName) TypeName(const TypeName&); void operator=(const TypeName&)class Foo public: Foo(int f); Foo();private: DISALLOW_COPY_AND_ASSIGN(Foo);如上所述,絕大多數(shù)情況下都應(yīng)使用DISALLOW_COPY_AND_ASSIGN,如果類確實(shí)需要可拷貝,應(yīng)在該類的頭文件中說(shuō)明原由,并適當(dāng)定義拷貝構(gòu)造函數(shù)和賦值操作,注意在operator=中檢測(cè)自賦值(self-assignment)情況。在將類作為STL容器值得時(shí)候,你可能有使類可拷貝的沖動(dòng)。類似情況下,真正該做的是使用指針指向STL容器中的對(duì)象,可以考慮使用std:tr1:shared_ptr。5. 結(jié)構(gòu)體和類(Structs vs. Classes)僅當(dāng)只有數(shù)據(jù)時(shí)使用struct,其它一概使用class。在C+中,關(guān)鍵字struct和class幾乎含義等同,我們?yōu)槠淙藶樘砑诱Z(yǔ)義,以便為定義的數(shù)據(jù)類型合理選擇使用哪個(gè)關(guān)鍵字。struct被用在僅包含數(shù)據(jù)的消極對(duì)象(passive objects)上,可能包括有關(guān)聯(lián)的常量,但沒(méi)有存取數(shù)據(jù)成員之外的函數(shù)功能,而存取功能通過(guò)直接訪問(wèn)實(shí)現(xiàn)而無(wú)需方法調(diào)用,這兒提到的方法是指只用于處理數(shù)據(jù)成員的,如構(gòu)造函數(shù)、析構(gòu)函數(shù)、Initialize()、Reset()、Validate()。如果需要更多的函數(shù)功能,class更適合,如果不確定的話,直接使用class。如果與STL結(jié)合,對(duì)于仿函數(shù)(functors)和特性(traits)可以不用class而是使用struct。注意:類和結(jié)構(gòu)體的成員變量使用不同的命名規(guī)則。6. 繼承(Inheritance)使用組合(composition,譯者注,這一點(diǎn)也是GoF在Design Patterns里反復(fù)強(qiáng)調(diào)的)通常比使用繼承更適宜,如果使用繼承的話,只使用公共繼承。定義:當(dāng)子類繼承基類時(shí),子類包含了父基類所有數(shù)據(jù)及操作的定義。C+實(shí)踐中,繼承主要用于兩種場(chǎng)合:實(shí)現(xiàn)繼承(implementation inheritance),子類繼承父類的實(shí)現(xiàn)代碼;接口繼承(interface inheritance),子類僅繼承父類的方法名稱。優(yōu)點(diǎn):實(shí)現(xiàn)繼承通過(guò)原封不動(dòng)的重用基類代碼減少了代碼量。由于繼承是編譯時(shí)聲明(compile-time declaration),編碼者和編譯器都可以理解相應(yīng)操作并發(fā)現(xiàn)錯(cuò)誤。接口繼承可用于程序上增強(qiáng)類的特定API的功能,在類沒(méi)有定義API的必要實(shí)現(xiàn)時(shí),編譯器同樣可以偵錯(cuò)。缺點(diǎn):對(duì)于實(shí)現(xiàn)繼承,由于實(shí)現(xiàn)子類的代碼在父類和子類間延展,要理解其實(shí)現(xiàn)變得更加困難。子類不能重寫(xiě)父類的非虛函數(shù),當(dāng)然也就不能修改其實(shí)現(xiàn)?;愐部赡芏x了一些數(shù)據(jù)成員,還要區(qū)分基類的物理輪廓(physical layout)。結(jié)論:所有繼承必須是public的,如果想私有繼承的話,應(yīng)該采取包含基類實(shí)例作為成員的方式作為替代。不要過(guò)多使用實(shí)現(xiàn)繼承,組合通常更合適一些。努力做到只在“是一個(gè)”(is-a,譯者注,其他has-a情況下請(qǐng)使用組合)的情況下使用繼承:如果Bar的確“是一種”Foo,才令Bar是Foo的子類。必要的話,令析構(gòu)函數(shù)為virtual,必要是指,如果該類具有虛函數(shù),其析構(gòu)函數(shù)應(yīng)該為虛函數(shù)。譯者注:至于子類沒(méi)有額外數(shù)據(jù)成員,甚至父類也沒(méi)有任何數(shù)據(jù)成員的特殊情況下,析構(gòu)函數(shù)的調(diào)用是否必要是語(yǔ)義爭(zhēng)論,從編程設(shè)計(jì)規(guī)范的角度看,在含有虛函數(shù)的父類中,定義虛析構(gòu)函數(shù)絕對(duì)必要。限定僅在子類訪問(wèn)的成員函數(shù)為protected,需要注意的是數(shù)據(jù)成員應(yīng)始終為私有。當(dāng)重定義派生的虛函數(shù)時(shí),在派生類中明確聲明其為virtual。根本原因:如果遺漏virtual,閱讀者需要檢索類的所有祖先以確定該函數(shù)是否為虛函數(shù)(譯者注,雖然不影響其為虛函數(shù)的本質(zhì))。7. 多重繼承(Multiple Inheritance)真正需要用到多重實(shí)現(xiàn)繼承(multiple implementation inheritance)的時(shí)候非常少,只有當(dāng)最多一個(gè)基類中含有實(shí)現(xiàn),其他基類都是以Interface為后綴的純接口類時(shí)才會(huì)使用多重繼承。定義:多重繼承允許子類擁有多個(gè)基類,要將作為純接口的基類和具有實(shí)現(xiàn)的基類區(qū)別開(kāi)來(lái)。優(yōu)點(diǎn):相比單繼承,多重實(shí)現(xiàn)繼承可令你重用更多代碼。缺點(diǎn):真正需要用到多重實(shí)現(xiàn)繼承的時(shí)候非常少,多重實(shí)現(xiàn)繼承看上去是不錯(cuò)的解決方案,通??梢哉业礁用鞔_、清晰的、不同的解決方案。結(jié)論:只有當(dāng)所有超類(superclass)除第一個(gè)外都是純接口時(shí)才能使用多重繼承。為確保它們是純接口,這些類必須以Interface為后綴。注意:關(guān)于此規(guī)則,Windows下有種例外情況(譯者注,將在本譯文最后一篇的規(guī)則例外中闡述)。8. 接口(Interface)接口是指滿足特定條件的類,這些類以Interface為后綴(非必需)。定義:當(dāng)一個(gè)類滿足以下要求時(shí),稱之為純接口:1) 只有純虛函數(shù)(=0)和靜態(tài)函數(shù)(下文提到的析構(gòu)函數(shù)除外);2) 沒(méi)有非靜態(tài)數(shù)據(jù)成員;3) 沒(méi)有定義任何構(gòu)造函數(shù)。如果有,也不含參數(shù),并且為protected;4) 如果是子類,也只能繼承滿足上述條件并以Interface為后綴的類。接口類不能被直接實(shí)例化,因?yàn)樗暶髁思兲摵瘮?shù)。為確保接口類的所有實(shí)現(xiàn)可被正確銷毀,必須為之聲明虛析構(gòu)函數(shù)(作為第1條規(guī)則的例外,析構(gòu)函數(shù)不能是純虛函數(shù))。具體細(xì)節(jié)可參考Stroustrup的The C+ Programming Language, 3rd edition第12.4節(jié)。優(yōu)點(diǎn):以Interface為后綴可令他人知道不能為該接口類增加實(shí)現(xiàn)函數(shù)或非靜態(tài)數(shù)據(jù)成員,這一點(diǎn)對(duì)于多重繼承尤其重要。另外,對(duì)于Java程序員來(lái)說(shuō),接口的概念已經(jīng)深入人心。缺點(diǎn):Interface后綴增加了類名長(zhǎng)度,為閱讀和理解帶來(lái)不便,同時(shí),接口特性作為實(shí)現(xiàn)細(xì)節(jié)不應(yīng)暴露給客戶。結(jié)論:。只有在滿足上述需要時(shí),類才以Interface結(jié)尾,但反過(guò)來(lái),滿足上述需要的類未必一定以Interface結(jié)尾。9. 操作符重載(Operator Overloading)除少數(shù)特定環(huán)境外,不要重載操作符。定義:一個(gè)類可以定義諸如+、/等操作符,使其可以像內(nèi)建類型一樣直接使用。優(yōu)點(diǎn):使代碼看上去更加直觀,就像內(nèi)建類型(如int)那樣,重載操作符使那些Equals()、Add()等黯淡無(wú)光的函數(shù)名好玩多了。為了使一些模板函數(shù)正確工作,你可能需要定義操作符。缺點(diǎn):雖然操作符重載令代碼更加直觀,但也有一些不足1) 混淆直覺(jué),讓你誤以為一些耗時(shí)的操作像內(nèi)建操作那樣輕巧;2) 查找重載操作符的調(diào)用處更加困難,查找Equals()顯然比同等調(diào)用=容易的多;3) 有的操作符可以對(duì)指針進(jìn)行操作,容易導(dǎo)致bugs,F(xiàn)oo + 4做的是一件事,而&Foo + 4可能做的是完全不同的另一件事,對(duì)于二者,編譯器都不會(huì)報(bào)錯(cuò),使其很難調(diào)試;4) 重載還有令你吃驚的副作用,比如,重載操作符&的類不能被前置聲明。結(jié)論:一般不要重載操作符,尤其是賦值操作(operator=)比較陰險(xiǎn),應(yīng)避免重載。如果需要的話,可以定義類似Equals()、CopyFrom()等函數(shù)。然而,極少數(shù)情況下需要重載操作符以便與模板或“標(biāo)準(zhǔn)”C+類銜接(如operator(ostream&, const T&)),如果被證明是正當(dāng)?shù)纳锌山邮?,但你要盡可能避免這樣做。尤其是不要僅僅為了在STL容器中作為key使用就重載operator=或operator實(shí)現(xiàn)繼承接口繼承私有繼承,子類重載的虛函數(shù)也要聲明virtual關(guān)鍵字,雖然編譯器允許不這樣做;7. 避免使用多重繼承,使用時(shí),除一個(gè)基類含有實(shí)現(xiàn)外,其他基類均為純接口;8. 接口類類名以Interface為后綴,除提供帶實(shí)現(xiàn)的虛析構(gòu)函數(shù)、靜態(tài)成員函數(shù)外,其他均為純虛函數(shù),不定義非靜態(tài)數(shù)據(jù)成員,不提供構(gòu)造函數(shù),提供的話,聲明為protected;9. 為降低復(fù)雜性,盡量不重載操作符,模板、標(biāo)準(zhǔn)類中使用時(shí)提供文檔說(shuō)明;10. 存取函數(shù)一般內(nèi)聯(lián)在頭文件中;11. 聲明次序:public-protected-private;12. 函數(shù)體盡量短小、緊湊,功能單一。 Google特有的風(fēng)情Google有很多自己實(shí)現(xiàn)的使C+代碼更加健壯的技巧、功能,以及有異于別處的C+的使用方式。1. 智能指針(Smart Pointers)如果確實(shí)需要使用智能指針的話,scoped_ptr完全可以勝任。在非常特殊的情況下,例如對(duì)STL容器中對(duì)象,你應(yīng)該只使用std:tr1:shared_ptr,任何情況下都不要使用auto_ptr?!爸悄堋敝羔樋瓷先ナ侵羔?,其實(shí)是附加了語(yǔ)義的對(duì)象。以scoped_ptr為例,scoped_ptr被銷毀時(shí),刪除了它所指向的對(duì)象。shared_ptr也是如此,而且,shared_ptr實(shí)現(xiàn)了引用計(jì)數(shù)(reference-counting),從而只有當(dāng)它所指向的最后一個(gè)對(duì)象被銷毀時(shí),指針才會(huì)被刪除。一般來(lái)說(shuō),我們傾向于設(shè)計(jì)對(duì)象隸屬明確的代碼,最明確的對(duì)象隸屬是根本不使用指針,直接將對(duì)象作為一個(gè)域(field)或局部變量使用。另一種極端是引用計(jì)數(shù)指針不屬于任何對(duì)象,這樣設(shè)計(jì)的問(wèn)題是容易導(dǎo)致循環(huán)引用或其他導(dǎo)致對(duì)象無(wú)法刪除的詭異條件,而且在每一次拷貝或賦值時(shí)連原子操作都會(huì)很慢。雖然不推薦這么做,但有些時(shí)候,引用計(jì)數(shù)指針是最簡(jiǎn)單有效的解決方案。譯者注:看來(lái),Google所謂的不同之處,在于盡量避免使用智能指針:D,使用時(shí)也盡量局部化,并且,安全第一。 其他C+特性1. 引用參數(shù)(Reference Arguments)所以按引用傳遞的參數(shù)必須加上const。定義:在C語(yǔ)言中,如果函數(shù)需要修改變量的值,形參(parameter)必須為指針,如int foo(int *pval)。在C+中,函數(shù)還可以聲明引用形參:int foo(int &val)。優(yōu)點(diǎn):定義形參為引用避免了像(*pval)+這樣丑陋的代碼,像拷貝構(gòu)造函數(shù)這樣的應(yīng)用也是必需的,而且不像指針那樣不接受空指針NULL。缺點(diǎn):容易引起誤解,因?yàn)橐迷谡Z(yǔ)法上是值卻擁有指針的語(yǔ)義。結(jié)論:函數(shù)形參表中,所有引用必須是const:void Foo(const string &in, string *out);事實(shí)上這是一個(gè)硬性約定:輸入?yún)?shù)為值或常數(shù)引用,輸出參數(shù)為指針;輸入?yún)?shù)可以是常數(shù)指針,但不能使用非常數(shù)引用形參。在強(qiáng)調(diào)參數(shù)不是拷貝而來(lái),在對(duì)象生命期內(nèi)必須一直存在時(shí)可以使用常數(shù)指針,最好將這些在注釋中詳細(xì)說(shuō)明。bind2nd和mem_fun等STL適配器不接受引用形參,這種情況下也必須以指針形參聲明函數(shù)。2. 函數(shù)重載(Function Overloading)僅在輸入?yún)?shù)類型不同、功能相同時(shí)使用重載函數(shù)(含構(gòu)造函數(shù)),不要使用函數(shù)重載模仿缺省函數(shù)參數(shù)。定義:可以定義一個(gè)函數(shù)參數(shù)類型為const string&,并定義其重載函數(shù)類型為const char*。class MyClass public: void Analyze(const string &text); void Analyze(const char *text, size_t textlen);優(yōu)點(diǎn):通過(guò)重載不同參數(shù)的同名函數(shù),令代碼更加直觀,模板化代碼需要重載,同時(shí)為訪問(wèn)者帶來(lái)便利。缺點(diǎn):限制使用重載的一個(gè)原因是在特定調(diào)用處很難確定到底調(diào)用的是哪個(gè)函數(shù),另一個(gè)原因是當(dāng)派生類只重載函數(shù)的部分變量會(huì)令很多人對(duì)繼承語(yǔ)義產(chǎn)生困惑。此外在閱讀庫(kù)的客戶端代碼時(shí),因缺省函數(shù)參數(shù)造成不必要的費(fèi)解。結(jié)論:如果你想重載一個(gè)函數(shù),考慮讓函數(shù)名包含參數(shù)信息,例如,使用AppendString()、AppendInt()而不是Append()。3. 缺省參數(shù)(Default Arguments)禁止使用缺省函數(shù)參數(shù)。優(yōu)點(diǎn):經(jīng)常用到一個(gè)函數(shù)帶有大量缺省值,偶爾會(huì)重寫(xiě)一下這些值,缺省參數(shù)為很少涉及的例外情況提供了少定義一些函數(shù)的方便。缺點(diǎn):大家經(jīng)常會(huì)通過(guò)查看現(xiàn)有代碼確定如何使用API,缺省參數(shù)使得復(fù)制粘貼以前的代碼難以呈現(xiàn)所有參數(shù),當(dāng)缺省參數(shù)不適用于新代碼時(shí)可能導(dǎo)致重大問(wèn)題。結(jié)論:所有參數(shù)必須明確指定,強(qiáng)制程序員考慮API和傳入的各參數(shù)值,避免使用可能不為程序員所知的缺省參數(shù)。4. 變長(zhǎng)數(shù)組和alloca(Variable-Length Arrays and alloca())禁止使用變長(zhǎng)數(shù)組和alloca()。優(yōu)點(diǎn):變長(zhǎng)數(shù)組具有渾然天成的語(yǔ)法,變長(zhǎng)數(shù)組和alloca()也都很高效。缺點(diǎn):變長(zhǎng)數(shù)組和alloca()不是標(biāo)準(zhǔn)C+的組成部分,更重要的是,它們?cè)诙褩#╯tack)上根據(jù)數(shù)據(jù)分配大小可能導(dǎo)致難以發(fā)現(xiàn)的內(nèi)存泄漏:“在我的機(jī)器上運(yùn)行的好好的,到了產(chǎn)品中卻莫名其妙的掛掉了”。結(jié)論:使用安全的分配器(allocator),如scoped_ptr/scoped_array。5. 友元(Friends)允許合理使用友元類及友元函數(shù)。通常將友元定義在同一文件下,避免讀者跑到其他文件中查找其對(duì)某個(gè)類私有成員的使用。經(jīng)常用到友元的一個(gè)地方是將FooBuilder聲明為Foo的友元,F(xiàn)ooBuilder以便可以正確構(gòu)造Foo的內(nèi)部狀態(tài),而無(wú)需將該狀態(tài)暴露出來(lái)。某些情況下,將一個(gè)單元測(cè)試用類聲明為待測(cè)類的友元會(huì)很方便。友元延伸了(但沒(méi)有打破)類的封裝界線,當(dāng)你希望只允許另一個(gè)類訪問(wèn)某個(gè)成員時(shí),使用友元通常比將其聲明為public要好得多。當(dāng)然,大多數(shù)類應(yīng)該只提供公共成員與其交互。6. 異常(Exceptions)不要使用C+異常。優(yōu)點(diǎn):1) 異常允許上層應(yīng)用決定如何處理在底層嵌套函數(shù)中發(fā)生的“不可能發(fā)生”的失敗,不像出錯(cuò)代碼的記錄那么模糊費(fèi)解;2) 應(yīng)用于其他很多現(xiàn)代語(yǔ)言中,引入異常使得C+與Python、Java及其他與C+相近的語(yǔ)言更加兼容;3) 許多C+第三方庫(kù)使用異常,關(guān)閉異常將導(dǎo)致難以與之結(jié)合;4) 異常是解決構(gòu)造函數(shù)失敗的唯一方案,雖然可以通過(guò)工廠函數(shù)(factory function)或Init()方法模擬異常,但他們分別需要堆分配或新的“非法”狀態(tài);5) 在測(cè)試框架(testing framework)中,異常確實(shí)很好用。缺點(diǎn):1) 在現(xiàn)有函數(shù)中添加throw語(yǔ)句時(shí),必須檢查所有調(diào)用處,即使它們至少具有基本的異常安全保護(hù),或者程序正常結(jié)束,永遠(yuǎn)不可能捕獲該異常。例如:if f() calls g() calls h(),h拋出被f捕獲的異常,g就要當(dāng)心了,避免沒(méi)有完全清理;2) 通俗一點(diǎn)說(shuō),異常會(huì)導(dǎo)致程序控制流(control flow)通過(guò)查看代碼無(wú)法確定:函數(shù)有可能在不確定的地方返回,從而導(dǎo)致代碼管理和調(diào)試?yán)щy,當(dāng)然,你可以通過(guò)規(guī)定何時(shí)何地如何使用異常來(lái)最小化的降低開(kāi)銷,卻給開(kāi)發(fā)人員帶來(lái)掌握這些規(guī)定的負(fù)擔(dān);3) 異常安全需要RAII和不同編碼實(shí)踐。輕松、正確編寫(xiě)異常安全代碼需要大量支撐。允許使用異常;4) 加入異常使二進(jìn)制執(zhí)行代碼體積變大,增加了編譯時(shí)長(zhǎng)(或許影響不大),還可能增加地址空間壓力;5) 異常的實(shí)用性可能會(huì)刺激開(kāi)發(fā)人員在不恰當(dāng)?shù)臅r(shí)候拋出異常,或者在不安全
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 智慧物流技術(shù)與實(shí)務(wù) 教案全套 潘艷君 項(xiàng)目1-6 智慧物流概述-智慧物流的綜合應(yīng)用
- 2025年環(huán)保產(chǎn)業(yè)園區(qū)產(chǎn)業(yè)集聚與協(xié)同發(fā)展中的環(huán)保產(chǎn)業(yè)綠色技術(shù)創(chuàng)新報(bào)告
- 2025年工業(yè)互聯(lián)網(wǎng)平臺(tái)數(shù)據(jù)清洗算法在智能教育領(lǐng)域的應(yīng)用對(duì)比報(bào)告
- 金融與投資行業(yè)洞察報(bào)告:2025年金融科技在金融衍生品交易中的應(yīng)用與創(chuàng)新
- 美妝行業(yè)個(gè)性化定制服務(wù)模式在美妝行業(yè)市場(chǎng)拓展中的應(yīng)用報(bào)告
- 2025年工業(yè)互聯(lián)網(wǎng)平臺(tái)RFID技術(shù)在智能工廠生產(chǎn)安全風(fēng)險(xiǎn)控制中的應(yīng)用報(bào)告
- 做微商的心得體會(huì)經(jīng)典十四篇
- 無(wú)人機(jī)傳感器技術(shù) 8.1.陀螺儀在航空領(lǐng)域及無(wú)人機(jī)飛控中的應(yīng)用
- 無(wú)人看守設(shè)備管理制度
- ktv安全風(fēng)險(xiǎn)管理制度
- 2025汾西礦業(yè)井下操作技能人員招聘300人(山西)筆試參考題庫(kù)附帶答案詳解析集合
- 伊春市紀(jì)委監(jiān)委所屬事業(yè)單位招聘筆試真題2024
- 2025餐廳管理與服務(wù)合同
- 2025年全國(guó)“銀行業(yè)金融消費(fèi)者權(quán)益保護(hù)”應(yīng)知應(yīng)會(huì)知識(shí)考試題與答案
- (期末復(fù)習(xí))常考知識(shí)清單(八大單元52個(gè)小知識(shí)點(diǎn))-2024-2025學(xué)年三年級(jí)下冊(cè)數(shù)學(xué)期末備考總復(fù)習(xí)(人教版)
- 社會(huì)工作者的政策與法律試題及答案
- 2025年時(shí)事政治試題庫(kù)(含答案)
- 2025年農(nóng)村經(jīng)濟(jì)發(fā)展考試試卷及答案
- 充電樁設(shè)備生產(chǎn)建設(shè)項(xiàng)目投資可行性報(bào)告
- T/CECS 10011-2022聚乙烯共混聚氯乙烯高性能雙壁波紋管材
- 2025屆江蘇省宿遷市名校八下數(shù)學(xué)期末檢測(cè)試題含解析
評(píng)論
0/150
提交評(píng)論