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

歸去來兮

 

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

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

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

std::size_t numDisks() 
const;

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

}
;
Directory::Directory()
{

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

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


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)  編輯 收藏 引用


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


導(dǎo)航

統(tǒng)計

常用鏈接

留言簿(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>
            一区二区在线观看av| 亚洲影院色无极综合| 夜夜嗨av一区二区三区网页| 精品成人在线| 黄色av成人| 在线观看中文字幕不卡| 怡红院精品视频| 在线免费观看一区二区三区| 黄色另类av| 伊人夜夜躁av伊人久久| 精品福利电影| 亚洲欧洲日本mm| 亚洲国产欧美一区二区三区久久 | 好看的日韩视频| 亚洲人午夜精品免费| 亚洲永久视频| 久久久亚洲国产美女国产盗摄| 免费在线欧美视频| 亚洲精选一区| 香蕉久久一区二区不卡无毒影院| 久久综合色8888| 欧美三级在线播放| 国内精品福利| 亚洲视频综合| 狼人天天伊人久久| 亚洲深夜影院| 欧美成人一二三| 国模吧视频一区| 亚洲一区二区高清| 欧美成人tv| 亚洲欧美精品在线观看| 欧美国产高潮xxxx1819| 国产一区二区欧美日韩| 一区二区三欧美| 欧美成人四级电影| 性18欧美另类| 欧美日韩美女在线观看| 亚洲激情视频| 亚洲影视在线播放| 欧美成人午夜视频| 欧美一区2区视频在线观看| 欧美美女bb生活片| 亚洲二区在线观看| 欧美在线播放视频| 日韩一级片网址| 欧美国产欧美亚洲国产日韩mv天天看完整 | 国产亚洲精品美女| 在线中文字幕不卡| 欧美成人国产一区二区| 午夜视频一区二区| 国产精品国产成人国产三级| 亚洲国产精品一区二区尤物区| 久久成人综合网| 亚洲视频精品在线| 欧美日韩在线观看一区二区三区 | 亚洲午夜精品网| 亚洲人被黑人高潮完整版| 午夜久久久久久久久久一区二区| 欧美日韩在线视频观看| 一区二区精品| 欧美va亚洲va日韩∨a综合色| 亚洲一区二区三区在线视频| 欧美日韩免费精品| 一区二区三区免费看| 亚洲精品之草原avav久久| 欧美大片专区| 亚洲人体影院| 最新高清无码专区| 欧美日韩国产综合在线| 亚洲自拍偷拍麻豆| 西瓜成人精品人成网站| 韩国久久久久| 亚洲电影在线看| 欧美精品色网| 亚洲制服少妇| 校园春色综合网| **性色生活片久久毛片| 亚洲盗摄视频| 欧美色视频在线| 久久国产夜色精品鲁鲁99| 久久激情五月激情| 亚洲乱码国产乱码精品精天堂 | 亚洲欧洲日本在线| 欧美日韩国产综合一区二区| 午夜精品久久一牛影视| 欧美在线日韩精品| 在线观看成人网| 最新高清无码专区| 国产精品看片资源| 欧美成人午夜影院| 欧美日韩一区二区视频在线观看| 午夜精品亚洲一区二区三区嫩草| 欧美黄在线观看| 狠狠色2019综合网| 亚洲高清在线观看| 国产精品ⅴa在线观看h| 久久精品综合| 欧美96在线丨欧| 亚洲制服欧美中文字幕中文字幕| 欧美一区午夜精品| 99v久久综合狠狠综合久久| 午夜精品美女自拍福到在线 | 欧美成人精品激情在线观看| 亚洲视频视频在线| 久久久久久香蕉网| 亚洲欧美日韩精品久久亚洲区| 久久精品二区亚洲w码| 99re热精品| 久久精品国产精品亚洲综合| 一本在线高清不卡dvd | 欧美a级一区| 亚洲桃花岛网站| 久久影音先锋| 久久久免费精品| 欧美三日本三级少妇三99| 你懂的国产精品永久在线| 国产精品视频xxxx| 99国产成+人+综合+亚洲欧美| 国产综合网站| 亚洲欧美日韩综合国产aⅴ| 亚洲天堂免费观看| 欧美日本在线看| 亚洲国产福利在线| 亚洲第一视频| 久久久久久亚洲精品杨幂换脸| 欧美一区二区三区免费观看视频 | 在线成人av.com| 亚洲欧美一区二区视频| 亚洲女性裸体视频| 欧美日韩天堂| 一区二区国产精品| 亚洲已满18点击进入久久| 欧美日本亚洲视频| 亚洲免费不卡| 亚洲午夜小视频| 国产精品jvid在线观看蜜臀 | 一本色道久久综合亚洲精品小说| 夜夜嗨一区二区| 欧美日韩一级视频| 亚洲性视频网站| 欧美一区三区三区高中清蜜桃| 国产精品入口尤物| 亚洲欧美三级伦理| 久久美女性网| 伊人成年综合电影网| 久久久91精品国产一区二区三区 | 欧美激情自拍| 噜噜噜噜噜久久久久久91| 黄色成人在线| 久久人人超碰| 亚洲第一页自拍| 夜夜嗨av一区二区三区中文字幕 | 国产综合亚洲精品一区二| 久久国产精品网站| 欧美国产日韩一区二区在线观看| 亚洲国产精品久久91精品| 欧美剧在线观看| 亚洲欧美日韩国产综合在线| 麻豆91精品| 一区二区三区不卡视频在线观看| 欧美肉体xxxx裸体137大胆| 亚洲欧美日韩国产一区二区三区| 开心色5月久久精品| 日韩视频在线观看免费| 国产日韩欧美麻豆| 欧美va天堂va视频va在线| 一区二区三区高清视频在线观看| 午夜精品视频一区| 亚洲高清免费| 国产精品成av人在线视午夜片| 久久成人18免费观看| 亚洲国产另类精品专区| 香蕉久久国产| 亚洲精品影院在线观看| 国产麻豆视频精品| 欧美99在线视频观看| 在线一区日本视频| 欧美高清hd18日本| 欧美在线视频观看| 99视频精品全部免费在线| 国产日韩一区二区三区在线| 免费观看成人| 欧美在线视频不卡| a91a精品视频在线观看| 免费在线欧美黄色| 久久国产视频网站| 亚洲一区在线观看免费观看电影高清 | 麻豆成人综合网| 亚洲一区二区三区在线| 亚洲国产一区二区三区高清 | 久久婷婷久久一区二区三区| 亚洲视频香蕉人妖| 亚洲国产天堂久久综合| 国产亚洲精品bv在线观看| 欧美视频二区36p| 欧美激情一区二区在线| 开元免费观看欧美电视剧网站| 亚洲一区中文字幕在线观看| 亚洲伦理在线观看| 亚洲每日更新|