青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

歸去來兮

 

Effective C++讀書筆記之三 :確定對象被使用前已先被初始化

關于對象初始化,c++似乎反復無常,例如:
int x;
在某些語境條件下保證初始化為0,而在另外一些語境下卻并沒有這個保證。而下邊這種情況:
class Point{
int x,y;
}
;

Point p;
p的成員函數有的時候被初始化(0),有的時候沒有被初始化。
現在,已經有了一些規則,對象的初始化何時會發生,何時不會發生。但是這些規則過于復雜,對我們的記憶有一定的挑戰,哈哈。
通常如果使用C part of C++而且初始化可能招致運行期成本,那就不保證發生初始化。一旦進入non-C parts of C++,規則有一些變化。這就是為啥array(C part of C++)不保證其內容被初始化,而vector(STL part of C++)卻有此保證。
我們的最佳處理狀態是,在使用任何對象之前先將它初始化。對于無任何成員的內置類型,必須手動完成此事:
int x = 0;   //對int進行初始化;
const char *text = " A C-style string";   //對指針進行初始化;
double d;
std::cin 
>> d;   //采用input stream的方式完成初始化;
至于內置類型以外的其他類型,初始化的責任落在了構造函數身上。規則很簡單:確保構造函數都將對象的每一個成員初始化。
這個規則很容易奉行,值得注意的是別混淆了賦值(assignment)和初始化(initialization)。考慮一個表現通訊簿的class:
class PhoneNumber{};
class ABEntry{    //Address Book Entry;
public:
ABEntry(
const std::string &name, const std::string &address, const std::list<PhoneNumber> &phones);
private:
std::
string theName;
std::
string tehAddress;
std::list
<PhoneNumber> thePhones;
int numTimesConsulted;
}
;

ABEntry::ABEntry(
const std::string &name, const std::string &address, std::list<PhoneNumber> &phones)
{//以下全是賦值(assignment),不是初始化(initialization);
theName = name;
theAddress 
= address;
thePhones 
= phones;
numTimesConsulted 
= 0;
}
ABEntry對象會帶給你期望的值,但不是最佳做法。C++規定:對象成員變量的初始化動作發生在進入構造函數本體之前。在ABEntry構造函數內,theName, theAddress, thePhone都不是被初始化,而是被賦值。初始化的時間發生的更早,發生于這些成員函數的default構造函數被自動調用之時(比進入ABEntry構造函數本體的時間更早)。但這對numTimesConsulted不為真,因為他屬于內置類型,不保證在你看到的那個賦值動作的時間點之前獲得初值。
ABEntry構造函數的一個較好寫法是,使用所謂的member initializatin list(成員函數初始列)替換賦值動作:
ABEntry::ABEntry(const std::string &name, const std::string &address,
 
const std::list<PhoneNumber> &phones)
: theName(name),
 theAddress(address),
 thePhones(phones), 
numTimesConsulted(
0)
{}//構造函數本體不需要任何動作
這個構造函數和上一個的結果相同,但是通常效率較高。基于賦值的那個版本首先調用default構造函數為theName, theAddress,和thePhones設立初值,然后立刻再對他們賦值。default的一切作為此刻都浪費了。成員初始列(member initianlization list)的做法避免了這一問題,因為初始列中針對各個變量設的實參,被拿去作為各個成員函數的實參。本例中theName以name為初值進行copy構造,theAddress以address為初值進行copy構造,thePhones以phones為初值進行copy構造。
對于大多數類型而言,比起先調用default構造函數再調用copy assignment操作符,單只調用一次copy構造函數是比較高效的,有事甚至高的多。對于內置類型,如numTimesConsulted,其初始化成本和賦值的成本相同,但為了一致性最好也通過成員初始列來進行初始化。同樣道理,如果我們想default構造一個成員變量,也可以使用成員初始列,只要指定nothing作為初始化列就行了,假設ABEntry有一個無參構造構造函數,我們可以實現如下:
ABEntry::ABEntry()
:theName(),             
//調用theName的構造函數
theAddress(),           //調用theAddress的構造函數
thePhones(),            //調用thePhomes的構造函數
numTimesConsulted(0)    //記得將此內置類型顯式定義為0
{}
此處記得一條規則,那就是在成員初始列中列出所有的成員變量,以免還得記住哪些成員變量可以無需初值。舉個例子,如numTimesConsulted屬于內置類型,如果(member initialization list)遺漏了他,他就沒有初值,因而可能開啟“不明確行為”的潘多拉盒子。
有些情況下,即使面對的是內置類型,也一定要使用初始列。如果成員變量是const或者reference,他們一定得需要賦初值,而不是賦值。為避免成員變量何時必須在成員初始列中初始化,何時不需要,最簡單的做法就是:總是使用成員初始列。
C++有著十分固定的“成員初始化次序”。是的,次序總是相同的:base classes總是先于derived classes被初始化,而class的成員變量總是以其聲明次序被初始化。讓我們在看一下ABEntry,其theName永遠先被初始化,然后是theAddress,之后thePhones,最后是numTimesConsulted,即使他們在member initialization list中以不同的順序出現,也不會有任何影響。為了避免迷惑,你在member initialization list中條列各個成員時,最好總是以其聲明次序為次序。
一旦我們已經 很小心的將內置型成員變量明確的加以初始化,而且也確保構造函數運用member initialization list初始化base classes和成員變量,那就剩下唯一的一件事情需要操心,就是:不同編譯單元內定義之non-local static對象的初始化次序。
所謂static對象,其壽命從被構造出來直到程序結束為止,因此stack和heap_based對象都被排除。這里所說的static對象包括global對象,定義于namespace對象內的對象,在class內,在函數內,以及在file內被聲明為static的對象。函數內的static對象稱為local static對象,其他則成為non-local static對象,程序結束時static對象會自動銷毀,也就是他們的析構函數會在main()結束時被調用。
所謂編譯單元(translation unit)是指產生單一目標文件(single object file)的那些源碼。基本上是單一源碼文件加上其所包含的頭文件。
現在,上面所涉及到的問題至少包括兩個源碼文件,每一個內含至少一個non-local static對象(也就是說對象是global,或者位于namespace內,或者class內,或者file作用域內被聲明為static)。問題是:如果某個編譯單元內的某個non-local static對象的初始化動作使用了另外一個編譯單元內的non-local static對象,他所使用的這個對象可能沒有初始化,因為C++對“不同編譯單元內的non-local static 對象”的初始化次序并沒有明確定義。
來個例子:
 假設有一個FileSystem class,它讓互聯網上的文件看起來像是本機。由于這個class使世界看起來像個單一文件系統,可能會產生一個特殊對象,位于global或namespace作用域內,象征單一文件系統:
class FileSystem{
public:

std::size_t numDisks() 
const;

}
;
extern FileSystem tfs;//預備給客戶使用的對象,tfs代表"the file system"
FileSystem對象絕不是一個無關痛癢的對象,因此客戶如果在theFileSystem對象構造完成前就使用他,會得到慘重的代價:
現在假設建立了一個class用以處理文件系統內部的目錄。很自然,他們會用上theFileSystem的對象:
class Directory{
public:
Directory();

}
;
Directory::Directory()
{

std::size_t disks 
= tfs.numDisks();

}
進一步假設,這些客戶決定創建一個directory對象,用來放置臨時文件:
Directory tempDir(params);//為臨時文件而做出的目錄
現在,初始化的重要作用顯示出來了,除非tfs在tempDir之前被初始化,否則tempDir的構造函數會用到尚未初始化的tfs。但是tfs和tempDir是不同的人在不同的時間創建出來的,他們是定義于不同編譯單元內地non-local static對象,如何能確認tfs在tempDir之前先被初始化?
哦,這是無法確認的。
一個小小的設計可以改變這種情形:將每一個non-local static 對象搬到自己的專屬函數內(該對象在此函數內被聲明為static)。這些函數返回一個reference用來指向他所包含的對象。然后用戶調用這些函數,而不是直接指涉這些對象。換句話就是non-local static對象被local static對象替換了。這個實現的基礎在于:C++保證,函數內的non-local static 對象會在函數被調用期間首次遇上該對象之定義式時被初始化。所以如果以函數調用替換直接訪問non-local static 對象,就獲得了保證,保證所得的那個reference將指向一個經歷初始化的對象。 此技術實現于上面的代碼如下:
class FileSystem{};//同前
FileSystem &tfs()//這個函數用來替換tfs對象;他在FileSystem中可能是個static。
{
static FileSystem fs;
return fs;
}

class Directory{};
Directory::Directory()
{

std::size_t disks 
= tfs().numDisks();

}

Directory 
&tempDir()
{
static Directory td;
return td;
}
修改之后,我們只是使用的是tfs()和tempDir(),而不是tfs和tempDir。也就是使用的是指向static的reference而不是static對象自身。
這樣的reference-returning函數往往十分單純:第一行定義并初始化一個local static對象,第二行返回他。當然,他是絕佳的inline候選,特別是經常被調用的話。但是,另一方面,任何一種non-const static對象,不論是local或者non-local,在多線程下“等待某事發生都會有麻煩的。處理這個麻煩的一種做法是:在程序的單線程啟動階段手工調用所有的reference-returning函數(??),這可消除與初始化有關的race condition。
為避免對象初始化之前過早的使用他們,你需要做的是三件事:手工初始化內置的non-member對象;使用member initialization list;在初始化次序不確定下加強你的設計。


Things to remember:
1.Manually initialize objects of built-in type, because C++only sometimes initializes them itself;
2.In a constructor, prefer to use the member initialization list to assigenment inside the body of the constructor. List data member in the initialization list in the same order they're declared  in the class.
3.Avoid initialization order problems across translation units by replacing non-local static objects with local static objects.

posted on 2008-12-30 11:06 Edmund 閱讀(379) 評論(0)  編輯 收藏 引用

導航

統計

常用鏈接

留言簿(1)

隨筆分類

隨筆檔案

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲欧美另类在线观看| 久久久精品免费视频| 一区二区三区欧美在线观看| 亚洲激情一区二区三区| 亚洲国产精品电影| 亚洲片在线资源| 99国产精品国产精品毛片| 欲色影视综合吧| 亚洲黑丝一区二区| 亚洲国产你懂的| 夜夜爽99久久国产综合精品女不卡| 亚洲国产黄色片| 99视频精品在线| 午夜欧美大片免费观看| 久久精品国产清高在天天线| 久久一二三四| 亚洲精品视频在线观看网站| 亚洲午夜激情免费视频| 久久久精品一品道一区| 欧美日韩免费观看一区=区三区| 欧美视频网址| 国产午夜精品全部视频播放| 亚洲国产精品久久久久秋霞影院| 在线视频欧美日韩精品| 欧美专区福利在线| 亚洲人成网站精品片在线观看| 亚洲午夜激情网页| 久热国产精品视频| 国产精品久久999| 亚洲国产精品毛片| 亚洲欧美怡红院| 欧美国产乱视频| 一区二区三区免费网站| 你懂的国产精品| 国产欧美精品va在线观看| 亚洲精品中文字幕女同| 欧美综合二区| 夜夜嗨av一区二区三区免费区| 久久精品国产亚洲精品| 欧美丝袜第一区| 亚洲国产日韩欧美综合久久| 玖玖玖免费嫩草在线影院一区| 亚洲伦理在线| 久久久亚洲影院你懂的| 国产精品久久777777毛茸茸| 最新国产乱人伦偷精品免费网站 | 国产日韩一级二级三级| 中日韩午夜理伦电影免费| 欧美成人dvd在线视频| 午夜久久tv| 国产精品毛片一区二区三区| 亚洲精品字幕| 欧美国产亚洲另类动漫| 久久一区二区三区四区| 国产永久精品大片wwwapp| 香蕉久久夜色精品| 亚洲一区二区三区色| 欧美午夜不卡在线观看免费| 一本色道久久综合亚洲精品高清| 亚洲成色999久久网站| 免费不卡亚洲欧美| 亚洲二区视频| 亚洲国产精品热久久| 欧美成人免费大片| 亚洲伦理网站| 日韩一级免费| 国产精品av免费在线观看| 亚洲影院污污.| 亚洲永久视频| 国产亚洲精品bt天堂精选| 久久精品一区二区三区不卡牛牛| 西西人体一区二区| 在线精品视频一区二区三四| 欧美插天视频在线播放| 欧美国产视频在线观看| 亚洲无亚洲人成网站77777| 亚洲一二三区在线| 韩国av一区二区三区| 亚洲成色777777在线观看影院 | 国产色视频一区| 你懂的国产精品| 欧美成人三级在线| 亚洲一级黄色| 久久精品国产91精品亚洲| 在线观看日韩av电影| 亚洲国产日韩综合一区| 国产精品久久久久久久久免费桃花| 欧美一区二区精品| 久久午夜精品一区二区| 夜夜嗨av一区二区三区| 新片速递亚洲合集欧美合集| 亚洲福利视频网站| 一区二区久久久久| 精品av久久707| 艳女tv在线观看国产一区| 黄色精品一二区| 亚洲黄色免费| 国产手机视频一区二区| 亚洲国产视频一区| 国产一区二区av| 亚洲三级免费观看| 免费日韩一区二区| 欧美视频在线免费看| 久久久女女女女999久久| 欧美精品在线看| 久久精品欧美日韩| 欧美日韩高清区| 免费高清在线一区| 国产精品视频自拍| 亚洲美女av电影| 亚洲国产美女久久久久| 香蕉久久夜色精品国产使用方法| 亚洲乱码久久| 久久久久久久综合日本| 欧美亚洲尤物久久| 欧美日韩国产首页在线观看| 女同性一区二区三区人了人一| 国产精品免费视频观看| 亚洲精品一区中文| 亚洲三级免费观看| 久久精品国产欧美激情| 欧美在线综合视频| 国产精品人人做人人爽人人添| 亚洲日本成人在线观看| 91久久精品一区二区别| 久久久久在线| 久久久综合激的五月天| 国产免费成人在线视频| 亚洲小说欧美另类社区| 在线综合视频| 欧美激情视频网站| 欧美黑人在线观看| 亚洲黄色大片| 免费人成网站在线观看欧美高清| 久久夜色精品一区| 激情欧美国产欧美| 久久久久久国产精品一区| 欧美中文字幕在线| 韩国av一区二区三区四区| 久久av一区二区三区亚洲| 久久久精品一品道一区| 韩日成人av| 老鸭窝91久久精品色噜噜导演| 蜜臀av性久久久久蜜臀aⅴ四虎| 影音先锋亚洲一区| 欧美大尺度在线| 亚洲精品免费电影| 亚洲图片欧洲图片日韩av| 国产精品久久久久久超碰| 亚洲欧美在线高清| 久久人人爽爽爽人久久久| 亚洲福利在线看| 欧美日韩国产二区| 亚洲伊人伊色伊影伊综合网| 久久九九99视频| 亚洲精美视频| 国产精品成av人在线视午夜片| 亚洲欧美999| 毛片精品免费在线观看| 亚洲美女电影在线| 欧美体内谢she精2性欧美| 亚洲欧美在线免费| 欧美二区在线看| 一区二区三区精品| 国产欧美一区二区三区沐欲| 久久综合九色综合欧美就去吻| 亚洲三级毛片| 欧美在线播放| 亚洲毛片在线看| 国产精品毛片a∨一区二区三区|国| 亚洲成色精品| 欧美日本一区二区高清播放视频| 一区二区久久久久| 美女视频黄a大片欧美| av成人毛片| 国产在线精品一区二区夜色| 欧美二区不卡| 欧美一级二级三级蜜桃| 亚洲激情综合| 久久女同精品一区二区| 亚洲色诱最新| 91久久国产综合久久91精品网站| 国产精品久久久久9999高清| 另类激情亚洲| 欧美在线观看视频一区二区| 一区二区免费在线播放| 欧美黄色一区二区| 欧美在线亚洲一区| 亚洲午夜在线视频| 亚洲黄一区二区三区| 国产一区二区三区黄视频| 欧美日韩在线高清| 免费人成精品欧美精品| 欧美在线一二三区| 亚洲欧美国产不卡| 一区二区三区精品视频| 亚洲精品影视| 亚洲国产精品久久久久婷婷老年| 久久久久久亚洲精品不卡4k岛国| 亚洲综合精品自拍|