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

歸去來(lái)兮

 

Effective C++讀書(shū)筆記之三 :確定對(duì)象被使用前已先被初始化

關(guān)于對(duì)象初始化,c++似乎反復(fù)無(wú)常,例如:
int x;
在某些語(yǔ)境條件下保證初始化為0,而在另外一些語(yǔ)境下卻并沒(méi)有這個(gè)保證。而下邊這種情況:
class Point{
int x,y;
}
;

Point p;
p的成員函數(shù)有的時(shí)候被初始化(0),有的時(shí)候沒(méi)有被初始化。
現(xiàn)在,已經(jīng)有了一些規(guī)則,對(duì)象的初始化何時(shí)會(huì)發(fā)生,何時(shí)不會(huì)發(fā)生。但是這些規(guī)則過(guò)于復(fù)雜,對(duì)我們的記憶有一定的挑戰(zhàn),哈哈。
通常如果使用C part of C++而且初始化可能招致運(yùn)行期成本,那就不保證發(fā)生初始化。一旦進(jìn)入non-C parts of C++,規(guī)則有一些變化。這就是為啥array(C part of C++)不保證其內(nèi)容被初始化,而vector(STL part of C++)卻有此保證。
我們的最佳處理狀態(tài)是,在使用任何對(duì)象之前先將它初始化。對(duì)于無(wú)任何成員的內(nèi)置類(lèi)型,必須手動(dòng)完成此事:
int x = 0;   //對(duì)int進(jìn)行初始化;
const char *text = " A C-style string";   //對(duì)指針進(jìn)行初始化;
double d;
std::cin 
>> d;   //采用input stream的方式完成初始化;
至于內(nèi)置類(lèi)型以外的其他類(lèi)型,初始化的責(zé)任落在了構(gòu)造函數(shù)身上。規(guī)則很簡(jiǎn)單:確保構(gòu)造函數(shù)都將對(duì)象的每一個(gè)成員初始化。
這個(gè)規(guī)則很容易奉行,值得注意的是別混淆了賦值(assignment)和初始化(initialization)。考慮一個(gè)表現(xiàn)通訊簿的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對(duì)象會(huì)帶給你期望的值,但不是最佳做法。C++規(guī)定:對(duì)象成員變量的初始化動(dòng)作發(fā)生在進(jìn)入構(gòu)造函數(shù)本體之前。在ABEntry構(gòu)造函數(shù)內(nèi),theName, theAddress, thePhone都不是被初始化,而是被賦值。初始化的時(shí)間發(fā)生的更早,發(fā)生于這些成員函數(shù)的default構(gòu)造函數(shù)被自動(dòng)調(diào)用之時(shí)(比進(jìn)入ABEntry構(gòu)造函數(shù)本體的時(shí)間更早)。但這對(duì)numTimesConsulted不為真,因?yàn)樗麑儆趦?nèi)置類(lèi)型,不保證在你看到的那個(gè)賦值動(dòng)作的時(shí)間點(diǎn)之前獲得初值。
ABEntry構(gòu)造函數(shù)的一個(gè)較好寫(xiě)法是,使用所謂的member initializatin list(成員函數(shù)初始列)替換賦值動(dòng)作:
ABEntry::ABEntry(const std::string &name, const std::string &address,
 
const std::list<PhoneNumber> &phones)
: theName(name),
 theAddress(address),
 thePhones(phones), 
numTimesConsulted(
0)
{}//構(gòu)造函數(shù)本體不需要任何動(dòng)作
這個(gè)構(gòu)造函數(shù)和上一個(gè)的結(jié)果相同,但是通常效率較高。基于賦值的那個(gè)版本首先調(diào)用default構(gòu)造函數(shù)為theName, theAddress,和thePhones設(shè)立初值,然后立刻再對(duì)他們賦值。default的一切作為此刻都浪費(fèi)了。成員初始列(member initianlization list)的做法避免了這一問(wèn)題,因?yàn)槌跏剂兄嗅槍?duì)各個(gè)變量設(shè)的實(shí)參,被拿去作為各個(gè)成員函數(shù)的實(shí)參。本例中theName以name為初值進(jìn)行copy構(gòu)造,theAddress以address為初值進(jìn)行copy構(gòu)造,thePhones以phones為初值進(jìn)行copy構(gòu)造。
對(duì)于大多數(shù)類(lèi)型而言,比起先調(diào)用default構(gòu)造函數(shù)再調(diào)用copy assignment操作符,單只調(diào)用一次copy構(gòu)造函數(shù)是比較高效的,有事甚至高的多。對(duì)于內(nèi)置類(lèi)型,如numTimesConsulted,其初始化成本和賦值的成本相同,但為了一致性最好也通過(guò)成員初始列來(lái)進(jìn)行初始化。同樣道理,如果我們想default構(gòu)造一個(gè)成員變量,也可以使用成員初始列,只要指定nothing作為初始化列就行了,假設(shè)ABEntry有一個(gè)無(wú)參構(gòu)造構(gòu)造函數(shù),我們可以實(shí)現(xiàn)如下:
ABEntry::ABEntry()
:theName(),             
//調(diào)用theName的構(gòu)造函數(shù)
theAddress(),           //調(diào)用theAddress的構(gòu)造函數(shù)
thePhones(),            //調(diào)用thePhomes的構(gòu)造函數(shù)
numTimesConsulted(0)    //記得將此內(nèi)置類(lèi)型顯式定義為0
{}
此處記得一條規(guī)則,那就是在成員初始列中列出所有的成員變量,以免還得記住哪些成員變量可以無(wú)需初值。舉個(gè)例子,如numTimesConsulted屬于內(nèi)置類(lèi)型,如果(member initialization list)遺漏了他,他就沒(méi)有初值,因而可能開(kāi)啟“不明確行為”的潘多拉盒子。
有些情況下,即使面對(duì)的是內(nèi)置類(lèi)型,也一定要使用初始列。如果成員變量是const或者reference,他們一定得需要賦初值,而不是賦值。為避免成員變量何時(shí)必須在成員初始列中初始化,何時(shí)不需要,最簡(jiǎn)單的做法就是:總是使用成員初始列。
C++有著十分固定的“成員初始化次序”。是的,次序總是相同的:base classes總是先于derived classes被初始化,而class的成員變量總是以其聲明次序被初始化。讓我們?cè)诳匆幌翧BEntry,其theName永遠(yuǎn)先被初始化,然后是theAddress,之后thePhones,最后是numTimesConsulted,即使他們?cè)趍ember initialization list中以不同的順序出現(xiàn),也不會(huì)有任何影響。為了避免迷惑,你在member initialization list中條列各個(gè)成員時(shí),最好總是以其聲明次序?yàn)榇涡颉?br>一旦我們已經(jīng) 很小心的將內(nèi)置型成員變量明確的加以初始化,而且也確保構(gòu)造函數(shù)運(yùn)用member initialization list初始化base classes和成員變量,那就剩下唯一的一件事情需要操心,就是:不同編譯單元內(nèi)定義之non-local static對(duì)象的初始化次序。
所謂static對(duì)象,其壽命從被構(gòu)造出來(lái)直到程序結(jié)束為止,因此stack和heap_based對(duì)象都被排除。這里所說(shuō)的static對(duì)象包括global對(duì)象,定義于namespace對(duì)象內(nèi)的對(duì)象,在class內(nèi),在函數(shù)內(nèi),以及在file內(nèi)被聲明為static的對(duì)象。函數(shù)內(nèi)的static對(duì)象稱為local static對(duì)象,其他則成為non-local static對(duì)象,程序結(jié)束時(shí)static對(duì)象會(huì)自動(dòng)銷(xiāo)毀,也就是他們的析構(gòu)函數(shù)會(huì)在main()結(jié)束時(shí)被調(diào)用。
所謂編譯單元(translation unit)是指產(chǎn)生單一目標(biāo)文件(single object file)的那些源碼。基本上是單一源碼文件加上其所包含的頭文件。
現(xiàn)在,上面所涉及到的問(wèn)題至少包括兩個(gè)源碼文件,每一個(gè)內(nèi)含至少一個(gè)non-local static對(duì)象(也就是說(shuō)對(duì)象是global,或者位于namespace內(nèi),或者class內(nèi),或者file作用域內(nèi)被聲明為static)。問(wèn)題是:如果某個(gè)編譯單元內(nèi)的某個(gè)non-local static對(duì)象的初始化動(dòng)作使用了另外一個(gè)編譯單元內(nèi)的non-local static對(duì)象,他所使用的這個(gè)對(duì)象可能沒(méi)有初始化,因?yàn)镃++對(duì)“不同編譯單元內(nèi)的non-local static 對(duì)象”的初始化次序并沒(méi)有明確定義。
來(lái)個(gè)例子:
 假設(shè)有一個(gè)FileSystem class,它讓互聯(lián)網(wǎng)上的文件看起來(lái)像是本機(jī)。由于這個(gè)class使世界看起來(lái)像個(gè)單一文件系統(tǒng),可能會(huì)產(chǎn)生一個(gè)特殊對(duì)象,位于global或namespace作用域內(nèi),象征單一文件系統(tǒng):
class FileSystem{
public:

std::size_t numDisks() 
const;

}
;
extern FileSystem tfs;//預(yù)備給客戶使用的對(duì)象,tfs代表"the file system"
FileSystem對(duì)象絕不是一個(gè)無(wú)關(guān)痛癢的對(duì)象,因此客戶如果在theFileSystem對(duì)象構(gòu)造完成前就使用他,會(huì)得到慘重的代價(jià):
現(xiàn)在假設(shè)建立了一個(gè)class用以處理文件系統(tǒng)內(nèi)部的目錄。很自然,他們會(huì)用上theFileSystem的對(duì)象:
class Directory{
public:
Directory();

}
;
Directory::Directory()
{

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

}
進(jìn)一步假設(shè),這些客戶決定創(chuàng)建一個(gè)directory對(duì)象,用來(lái)放置臨時(shí)文件:
Directory tempDir(params);//為臨時(shí)文件而做出的目錄
現(xiàn)在,初始化的重要作用顯示出來(lái)了,除非tfs在tempDir之前被初始化,否則tempDir的構(gòu)造函數(shù)會(huì)用到尚未初始化的tfs。但是tfs和tempDir是不同的人在不同的時(shí)間創(chuàng)建出來(lái)的,他們是定義于不同編譯單元內(nèi)地non-local static對(duì)象,如何能確認(rèn)tfs在tempDir之前先被初始化?
哦,這是無(wú)法確認(rèn)的。
一個(gè)小小的設(shè)計(jì)可以改變這種情形:將每一個(gè)non-local static 對(duì)象搬到自己的專(zhuān)屬函數(shù)內(nèi)(該對(duì)象在此函數(shù)內(nèi)被聲明為static)。這些函數(shù)返回一個(gè)reference用來(lái)指向他所包含的對(duì)象。然后用戶調(diào)用這些函數(shù),而不是直接指涉這些對(duì)象。換句話就是non-local static對(duì)象被local static對(duì)象替換了。這個(gè)實(shí)現(xiàn)的基礎(chǔ)在于:C++保證,函數(shù)內(nèi)的non-local static 對(duì)象會(huì)在函數(shù)被調(diào)用期間首次遇上該對(duì)象之定義式時(shí)被初始化。所以如果以函數(shù)調(diào)用替換直接訪問(wèn)non-local static 對(duì)象,就獲得了保證,保證所得的那個(gè)reference將指向一個(gè)經(jīng)歷初始化的對(duì)象。 此技術(shù)實(shí)現(xiàn)于上面的代碼如下:
class FileSystem{};//同前
FileSystem &tfs()//這個(gè)函數(shù)用來(lái)替換tfs對(duì)象;他在FileSystem中可能是個(gè)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對(duì)象自身。
這樣的reference-returning函數(shù)往往十分單純:第一行定義并初始化一個(gè)local static對(duì)象,第二行返回他。當(dāng)然,他是絕佳的inline候選,特別是經(jīng)常被調(diào)用的話。但是,另一方面,任何一種non-const static對(duì)象,不論是local或者non-local,在多線程下“等待某事發(fā)生都會(huì)有麻煩的。處理這個(gè)麻煩的一種做法是:在程序的單線程啟動(dòng)階段手工調(diào)用所有的reference-returning函數(shù)(??),這可消除與初始化有關(guān)的race condition。
為避免對(duì)象初始化之前過(guò)早的使用他們,你需要做的是三件事:手工初始化內(nèi)置的non-member對(duì)象;使用member initialization list;在初始化次序不確定下加強(qiáng)你的設(shè)計(jì)。


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) 評(píng)論(0)  編輯 收藏 引用


只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


導(dǎo)航

統(tǒng)計(jì)

常用鏈接

留言簿(1)

隨筆分類(lèi)

隨筆檔案

搜索

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            国产精品剧情在线亚洲| 亚洲欧美www| 欧美主播一区二区三区美女 久久精品人 | 国产欧美一区二区精品忘忧草| 欧美久久久久久久久| 欧美人在线观看| 国产精品qvod| 国产色爱av资源综合区| 国产一区二区三区无遮挡| 一区二区三区我不卡| 亚洲欧洲久久| 亚洲主播在线观看| 久久日韩精品| 卡一卡二国产精品| 午夜精品久久久久影视| 久久国产精品一区二区三区四区 | 欧美va亚洲va日韩∨a综合色| 免费在线播放第一区高清av| 亚洲国产专区校园欧美| 亚洲日本一区二区三区| 亚洲婷婷综合久久一本伊一区| 西西裸体人体做爰大胆久久久| 久久综合伊人| 欧美三级在线视频| 在线观看视频一区二区欧美日韩 | 亚洲第一色在线| 亚洲视频综合在线| 美女精品国产| 亚洲男人的天堂在线| 欧美~级网站不卡| 国产性猛交xxxx免费看久久| 99riav1国产精品视频| 久久午夜电影| 亚洲一区二区高清| 欧美成人国产| 国内精品一区二区三区| 亚洲综合日韩在线| 亚洲精品无人区| 欧美h视频在线| 伊人久久大香线蕉av超碰演员| 亚洲欧美日本视频在线观看| 亚洲人成亚洲人成在线观看图片| 久久精品一区二区三区中文字幕| 欧美日韩亚洲一区二区三区在线观看| 精品动漫3d一区二区三区免费版| 欧美一级黄色网| 亚洲毛片av在线| 欧美成人午夜视频| 亚洲大胆av| 免费人成网站在线观看欧美高清| 香蕉久久夜色精品国产使用方法| 国产精品乱人伦中文| 亚洲一区国产| 亚洲美女视频网| 欧美激情在线观看| 亚洲人成在线观看网站高清| 免费中文字幕日韩欧美| 久久黄色影院| 一区二区视频在线观看| 老司机久久99久久精品播放免费| 欧美一级大片在线免费观看| 国产欧美亚洲视频| 久久天堂av综合合色| 久久精品国语| 亚洲第一免费播放区| 欧美激情在线免费观看| 欧美国产一区二区| 久久亚洲二区| 久久精品国产清高在天天线| 国产精品捆绑调教| 亚洲日本在线视频观看| 亚洲国产日韩一区二区| 欧美精品在线免费观看| 一本色道久久综合亚洲精品婷婷| 亚洲区一区二区三区| 欧美成人综合一区| 在线一区二区三区四区五区| 日韩视频一区二区三区在线播放免费观看| 欧美好骚综合网| 亚洲欧美另类综合偷拍| 性欧美videos另类喷潮| 伊人婷婷久久| 亚洲日本中文字幕| 国产日韩在线亚洲字幕中文| 免费观看30秒视频久久| 欧美日韩亚洲一区二| 欧美在线免费观看视频| 久久伊人一区二区| 一区二区三区视频在线播放| 亚洲欧美激情视频| 亚洲高清久久久| 一区二区三区福利| 加勒比av一区二区| 亚洲精品久久久久久久久久久久| 国产精品私房写真福利视频| 免费观看国产成人| 国产精品美女www爽爽爽视频 | 久久久蜜臀国产一区二区| 免费成人高清| 亚洲欧美日韩国产中文| 老司机亚洲精品| 午夜欧美精品| 欧美成人免费网站| 久久久www成人免费毛片麻豆| 欧美激情国产精品| 久久视频在线视频| 国产精品久久久久久久久久妞妞| 欧美成人福利视频| 国产区二精品视| 夜夜嗨av一区二区三区网页| 国产亚洲精品久| 99精品福利视频| 最新热久久免费视频| 亚洲欧美成人一区二区在线电影| 亚洲国产精品久久久久秋霞不卡| 中文日韩在线| 日韩一区二区精品| 麻豆av一区二区三区| 久久精品一区四区| 国产精品在线看| 中文日韩欧美| 亚洲在线网站| 欧美精品久久久久久久久老牛影院 | 久热re这里精品视频在线6| 欧美成人在线免费观看| 很黄很黄激情成人| 亚洲欧美日韩区| 亚洲欧美综合一区| 欧美视频久久| 亚洲欧洲一区二区三区久久| 一区二区三区在线视频免费观看 | 久久久精品国产99久久精品芒果| 亚洲欧美日韩综合aⅴ视频| 欧美人与禽猛交乱配| 亚洲人成亚洲人成在线观看| 亚洲黄色一区二区三区| 每日更新成人在线视频| 欧美成人综合一区| 亚洲国产成人高清精品| 久久露脸国产精品| 免费一区视频| 亚洲精品一区二区在线| 欧美激情第一页xxx| 亚洲乱码日产精品bd| 亚洲视频在线一区观看| 国产精品美女999| 欧美在线播放高清精品| 免费久久精品视频| 亚洲肉体裸体xxxx137| 欧美黄免费看| 一区二区三区精品国产| 欧美一区二区视频网站| 狠狠色综合网| 欧美电影免费观看大全| aa成人免费视频| 欧美在线一二三区| 国内精品久久久久久久影视蜜臀 | 国产精品久久久久永久免费观看 | 国产一区二区高清| 久久精品国产一区二区电影| 免费亚洲一区| 亚洲一区二区三区免费视频| 国产日产欧美一区| 久久综合电影| 亚洲精品视频免费在线观看| 亚洲欧美日本日韩| 亚洲国产精品久久久久秋霞蜜臀 | 欧美三级网址| 欧美一区深夜视频| 亚洲国产精品视频一区| 亚洲欧美日韩成人| 亚洲国产精品女人久久久| 欧美日韩国产成人| 亚洲欧美精品在线| 亚洲国产成人精品久久久国产成人一区| av成人免费观看| 国产午夜亚洲精品不卡| 欧美激情精品久久久久久蜜臀| 一区二区三区国产| 亚洲成色精品| 欧美呦呦网站| 西西裸体人体做爰大胆久久久| 欧美69视频| 91久久综合| 欧美日韩亚洲一区二区三区在线| 欧美一区二区福利在线| 亚洲日本在线观看| 美女精品国产| 欧美一区二区三区免费视频| 亚洲精品激情| 国内外成人在线视频| 欧美日韩在线播放三区| 你懂的国产精品| 欧美中文字幕第一页| 一区二区三区日韩精品视频| 亚洲国产成人av在线| 久久深夜福利免费观看| 午夜视频在线观看一区| 亚洲色无码播放| 99国内精品|