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

Beginning to 編程

VC++ 方面編程文章

 

EffectiveC++2ed 關(guān)于函數(shù)返回對(duì)象,引用還是指針

我看到EffectiveC++2ed中函數(shù)返回對(duì)象中的說明感覺以后再也不想讓返回任何東西啦。比較怕。

但是有的時(shí)候不返回任何東西是不行的阿。

返回引用,返回指針,返回對(duì)象到底怎么寫?!

——————————————————————————————
下面是EC中的內(nèi)容

條款23: 必須返回一個(gè)對(duì)象時(shí)不要試圖返回一個(gè)引用

據(jù)說愛因斯坦曾提出過這樣的建議:盡可能地讓事情簡(jiǎn)單,但不要過于簡(jiǎn)單。在c++語言中相似的說法應(yīng)該是:盡可能地使程序高效,但不要過于高效。

一旦程序員抓住了“傳值”在效率上的把柄(參見條款22),他們會(huì)變得十分極端,恨不得挖出每一個(gè)隱藏在程序中的傳值操作。豈不知,在他們不懈地追求純粹的“傳引用”的過程中,他們會(huì)不可避免地犯另一個(gè)嚴(yán)重的錯(cuò)誤:傳遞一個(gè)并不存在的對(duì)象的引用。這就不是好事了。

看一個(gè)表示有理數(shù)的類,其中包含一個(gè)友元函數(shù),用于兩個(gè)有理數(shù)相乘:

class rational {
public:
? rational(int numerator = 0, int denominator = 1);

? ...

private:
? int n, d;????????????? // 分子和分母

friend
? const rational????????????????????? // 參見條款21:為什么
??? operator*(const rational& lhs,??? // 返回值是const
????????????? const rational& rhs)????
};

inline const rational operator*(const rational& lhs,
??????????????????????????????? const rational& rhs)
{
? return rational(lhs.n * rhs.n, lhs.d * rhs.d);
}

很明顯,這個(gè)版本的operator*是通過傳值返回對(duì)象結(jié)果,如果不去考慮對(duì)象構(gòu)造和析構(gòu)時(shí)的開銷,你就是在逃避作為一個(gè)程序員的責(zé)任。另外一件很明顯的事實(shí)是,除非確實(shí)有必要,否則誰都不愿意承擔(dān)這樣一個(gè)臨時(shí)對(duì)象的開銷。那么,問題就歸結(jié)于:確實(shí)有必要嗎?

答案是,如果能返回一個(gè)引用,當(dāng)然就沒有必要。但請(qǐng)記住,引用只是一個(gè)名字,一個(gè)其它某個(gè)已經(jīng)存在的對(duì)象的名字。無論何時(shí)看到一個(gè)引用的聲明,就要立即問自己:它的另一個(gè)名字是什么呢?因?yàn)樗厝贿€有另外一個(gè)什么名字(見條款m1)。拿operator*來說,如果函數(shù)要返回一個(gè)引用,那它返回的必須是其它某個(gè)已經(jīng)存在的rational對(duì)象的引用,這個(gè)對(duì)象包含了兩個(gè)對(duì)象相乘的結(jié)果。

但,期望在調(diào)用operator*之前有這樣一個(gè)對(duì)象存在是沒道理的。也就是說,如果有下面的代碼:

rational a(1, 2);??????????????? // a = 1/2
rational b(3, 5);??????????????? // b = 3/5
rational c = a * b;????????????? // c 為 3/10

期望已經(jīng)存在一個(gè)值為3/10的有理數(shù)是不現(xiàn)實(shí)的。如果operator* 一定要返回這樣一個(gè)數(shù)的引用,就必須自己創(chuàng)建這個(gè)數(shù)的對(duì)象。

一個(gè)函數(shù)只能有兩種方法創(chuàng)建一個(gè)新對(duì)象:在堆棧里或在堆上。在堆棧里創(chuàng)建對(duì)象時(shí)伴隨著一個(gè)局部變量的定義,采用這種方法,就要這樣寫operator*:

// 寫此函數(shù)的第一個(gè)錯(cuò)誤方法
inline const rational& operator*(const rational& lhs,
???????????????????????????????? const rational& rhs)
{
? rational result(lhs.n * rhs.n, lhs.d * rhs.d);
? return result;
}

這個(gè)方法應(yīng)該被否決,因?yàn)槲覀兊哪繕?biāo)是避免構(gòu)造函數(shù)被調(diào)用,但result必須要象其它對(duì)象一樣被構(gòu)造。另外,這個(gè)函數(shù)還有另外一個(gè)更嚴(yán)重的問題,它返回的是一個(gè)局部對(duì)象的引用,關(guān)于這個(gè)錯(cuò)誤,條款31進(jìn)行了深入的討論。

那么,在堆上創(chuàng)建一個(gè)對(duì)象然后返回它的引用呢?基于堆的對(duì)象是通過使用new產(chǎn)生的,所以應(yīng)該這樣寫operator*:

// 寫此函數(shù)的第二個(gè)錯(cuò)誤方法
inline const rational& operator*(const rational& lhs,
???????????????????????????????? const rational& rhs)
{
? rational *result =
??? new rational(lhs.n * rhs.n, lhs.d * rhs.d);
? return *result;
}

首先,你還是得負(fù)擔(dān)構(gòu)造函數(shù)調(diào)用的開銷,因?yàn)閚ew分配的內(nèi)存是通過調(diào)用一個(gè)適當(dāng)?shù)臉?gòu)造函數(shù)來初始化的(見條款5和m8)。另外,還有一個(gè)問題:誰將負(fù)責(zé)用delete來刪除掉new生成的對(duì)象呢?

實(shí)際上,這絕對(duì)是一個(gè)內(nèi)存泄漏。即使可以說服operator*的調(diào)用者去取函數(shù)返回值地址,然后用delete去刪除它(絕對(duì)不可能——條款31展示了這樣的代碼會(huì)是什么樣的),但一些復(fù)雜的表達(dá)式會(huì)產(chǎn)生沒有名字的臨時(shí)值,程序員是不可能得到的。例如:

rational w, x, y, z;

w = x * y * z;

兩個(gè)對(duì)operator*的調(diào)用都產(chǎn)生了沒有名字的臨時(shí)值,程序員無法看到,因而無法刪除。(再次參見條款31)

也許,你會(huì)想你比一般的熊——或一般的程序員——要聰明;也許,你注意到在堆棧和堆上創(chuàng)建對(duì)象的方法避免不了對(duì)構(gòu)造函數(shù)的調(diào)用;也許,你想起了我們最初的目標(biāo)是為了避免這種對(duì)構(gòu)造函數(shù)的調(diào)用;也許,你有個(gè)辦法可以只用一個(gè)構(gòu)造函數(shù)來搞掂一切;也許,你的眼前出現(xiàn)了這樣一段代碼:operator*返回一個(gè)“在函數(shù)內(nèi)部定義的靜態(tài)rational對(duì)象”的引用:

// 寫此函數(shù)的第三個(gè)錯(cuò)誤方法
inline const rational& operator*(const rational& lhs,
???????????????????????????????? const rational& rhs)
{
? static rational result;????? // 將要作為引用返回的
?????????????????????????????? // 靜態(tài)對(duì)象

? lhs和rhs 相乘,結(jié)果放進(jìn)result;

? return result;
}

這個(gè)方法看起來好象有戲,雖然在實(shí)際實(shí)現(xiàn)上面的偽代碼時(shí)你會(huì)發(fā)現(xiàn),不調(diào)用一個(gè)rational構(gòu)造函數(shù)是不可能給出result的正確值的,而避免這樣的調(diào)用正是我們要談?wù)摰闹黝}。就算你實(shí)現(xiàn)了上面的偽代碼,但,你再聰明也不能最終挽救這個(gè)不幸的設(shè)計(jì)。

想知道為什么,看看下面這段寫得很合理的用戶代碼:

bool operator==(const rational& lhs,????? // rationals的operator==
??????????????? const rational& rhs);???? //

rational a, b, c, d;

...

if ((a * b) == (c * d)) {

? 處理相等的情況;

} else {

? 處理不相等的情況;

}

看出來了嗎?((a*b) == (c*d)) 會(huì)永遠(yuǎn)為true,不管a,b,c和d是什么值!

用等價(jià)的函數(shù)形式重寫上面的相等判斷語句就很容易明白發(fā)生這一可惡行為的原因了:

if (operator==(operator*(a, b), operator*(c, d)))

注意當(dāng)operator==被調(diào)用時(shí),總有兩個(gè)operator*剛被調(diào)用,每個(gè)調(diào)用返回operator*內(nèi)部的靜態(tài)rational對(duì)象的引用。于是,上面的語句實(shí)際上是請(qǐng)求operator==對(duì)“operator*內(nèi)部的靜態(tài)rational對(duì)象的值”和“operator*內(nèi)部的靜態(tài)rational對(duì)象的值”進(jìn)行比較,這樣的比較不相等才怪呢!

幸運(yùn)的話,我以上的說明應(yīng)該足以說服你:想“在象operator*這樣的函數(shù)里返回一個(gè)引用”實(shí)際上是在浪費(fèi)時(shí)間。但我沒幼稚到會(huì)相信幸運(yùn)總會(huì)光臨自己。一些人——你們知道這些人是指誰——此刻會(huì)在想,“唔,上面那個(gè)方法,如果一個(gè)靜態(tài)變量不夠用,也許可以用一個(gè)靜態(tài)數(shù)組……”

請(qǐng)就此打住!我們難道還沒受夠嗎?

我不能讓自己寫一段示例代碼來太高這個(gè)設(shè)計(jì),因?yàn)榧词怪槐в猩厦孢@種想法都足以令人感到羞愧。首先,你必須選擇一個(gè)n,指定數(shù)組的大小。如果n太小,就會(huì)沒地方儲(chǔ)存函數(shù)返回值,這和我們前面否定的那個(gè)“采用單個(gè)靜態(tài)變量的設(shè)計(jì)”相比沒有什么改進(jìn)。如果n太大,就會(huì)降低程序的性能,因?yàn)楹瘮?shù)第一次被調(diào)用時(shí)數(shù)組中每個(gè)對(duì)象都要被創(chuàng)建。這會(huì)帶來n個(gè)構(gòu)造函數(shù)和n個(gè)析構(gòu)函數(shù)的開銷,即使這個(gè)函數(shù)只被調(diào)用一次。如果說"optimization"(最優(yōu)化)是指提高軟件的性能的過程, 那么現(xiàn)在這種做法簡(jiǎn)直可以稱為"pessimization"(最差化)。最后,想想怎么把需要的值放到數(shù)組的對(duì)象中以及需要多大的開銷?在對(duì)象間傳值的最直接的方法是通過賦值,但賦值的開銷又有多大呢?一般來說,它相當(dāng)于調(diào)用一個(gè)析構(gòu)函數(shù)(摧毀舊值)再加上調(diào)用一個(gè)構(gòu)造函數(shù)(拷貝新值)。但我們現(xiàn)在的目標(biāo)正是為了避免構(gòu)造和析構(gòu)的開銷啊!面對(duì)現(xiàn)實(shí)吧:這個(gè)方法也絕對(duì)不能選用。

所以,寫一個(gè)必須返回一個(gè)新對(duì)象的函數(shù)的正確方法就是讓這個(gè)函數(shù)返回一個(gè)新對(duì)象。對(duì)于rational的operator*來說,這意味著要不就是下面的代碼(就是最初看到的那段代碼),要不就是本質(zhì)上和它等價(jià)的代碼:

inline const rational operator*(const rational& lhs,
??????????????????????????????? const rational& rhs)
{
? return rational(lhs.n * rhs.n, lhs.d * rhs.d);
}

的確,這會(huì)導(dǎo)致“operator*的返回值構(gòu)造和析構(gòu)時(shí)帶來的開銷”,但歸根結(jié)底它只是用小的代價(jià)換來正確的程序運(yùn)行行為而已。況且,你所擔(dān)心的開銷還有可能永遠(yuǎn)不會(huì)出現(xiàn):和所有程序設(shè)計(jì)語言一樣,c++允許編譯器的設(shè)計(jì)者采用一些優(yōu)化措施來提高所生成的代碼的性能,所以,在有些場(chǎng)合,operator*的返回值會(huì)被安全地除去(見條款m20)。當(dāng)編譯器采用了這種優(yōu)化時(shí)(當(dāng)前大部分編譯器這么做),程序和以前一樣繼續(xù)工作,只不過是運(yùn)行速度比你預(yù)計(jì)的要快而已。

以上討論可以歸結(jié)為:當(dāng)需要在返回引用和返回對(duì)象間做決定時(shí),你的職責(zé)是選擇可以完成正確功能的那個(gè)。至于怎么讓這個(gè)選擇所產(chǎn)生的代價(jià)盡可能的小,那是編譯器的生產(chǎn)商去想的事。

posted on 2006-03-24 15:51 Beginning to 編程 閱讀(2950) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 心得體會(huì)

導(dǎo)航

統(tǒng)計(jì)

常用鏈接

留言簿(4)

隨筆分類

隨筆檔案

文章檔案

相冊(cè)

BlogDev

搜索

最新評(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>
            欧美伦理一区二区| 日韩亚洲欧美中文三级| 欧美一区三区二区在线观看| 亚洲一区二区视频在线| 亚洲性图久久| 性娇小13――14欧美| 欧美影视一区| 欧美+日本+国产+在线a∨观看| 久久亚洲春色中文字幕| 欧美激情视频在线播放| 国产精品高潮粉嫩av| 国产精品一卡二| 国产私拍一区| 亚洲人成小说网站色在线| 亚洲国产一区二区精品专区| 亚洲美女在线观看| 亚洲伊人伊色伊影伊综合网| 久久久国产精品一区二区中文 | 久久精品国亚洲| 女人香蕉久久**毛片精品| 欧美日韩视频第一区| 国产手机视频一区二区| 日韩网站在线看片你懂的| 亚洲欧美日韩在线| 欧美v日韩v国产v| 99视频精品在线| 久久久午夜电影| 国产精品成人观看视频免费| 激情综合视频| 亚洲欧美日韩视频二区| 欧美国产成人精品| 午夜精品在线| 欧美日本精品在线| 激情亚洲成人| 欧美亚洲一区二区三区| 亚洲激情国产| 亚洲三级影片| 裸体丰满少妇做受久久99精品| 欧美日韩在线高清| 最新中文字幕一区二区三区| 欧美专区福利在线| 99精品热视频| 欧美激情综合亚洲一二区| 伊人婷婷久久| 久久国产精品99国产精| 夜夜精品视频一区二区| 欧美xxx在线观看| 影音先锋久久资源网| 欧美在线看片a免费观看| 国产精品永久免费在线| 激情文学一区| 亚洲免费在线电影| 欧美激情在线有限公司| 欧美在线欧美在线| 国产精品久久久91| 在线亚洲免费视频| 亚洲国产婷婷香蕉久久久久久| 午夜精品久久久久久久白皮肤| 欧美喷潮久久久xxxxx| 亚洲国产精品久久久| 裸体丰满少妇做受久久99精品| 午夜精品亚洲| 国产在线不卡| 久久一区二区三区四区| 久久九九热re6这里有精品| 国内精品模特av私拍在线观看| 欧美在线视频日韩| 欧美在线黄色| 永久555www成人免费| 欧美成黄导航| 欧美另类专区| 亚洲资源av| 中文一区在线| 国产免费成人av| 午夜宅男欧美| 久久国产精品久久国产精品| 国产亚洲人成网站在线观看| 久久视频这里只有精品| 久久天天躁夜夜躁狠狠躁2022| 亚洲国产精品免费| 亚洲免费电影在线观看| 国产精品亚洲一区| 欧美/亚洲一区| 欧美日韩美女| 久久精品亚洲热| 嫩草成人www欧美| 亚洲综合国产| 欧美一区二区视频网站| 亚洲国产精品电影| 在线视频欧美日韩| 国产又爽又黄的激情精品视频| 欧美国产免费| 国产精品国产三级欧美二区| 久久久久久久激情视频| 免费在线观看一区二区| 国自产拍偷拍福利精品免费一| 欧美高清在线观看| 国产精品理论片| 亚洲二区免费| 国产女人精品视频| 亚洲第一区在线| 国产日本欧美一区二区三区在线| 欧美高清视频一区| 国产午夜精品在线观看| 亚洲激情影视| 黄色成人在线网址| 日韩视频在线观看国产| 国产一区二区三区在线观看网站| 久久九九99视频| 亚洲欧美在线一区| 久久电影一区| 亚洲国产日韩欧美在线图片| 一本色道88久久加勒比精品| 伊人成人开心激情综合网| 亚洲免费网址| 亚洲私人黄色宅男| 免费黄网站欧美| 久久久久久亚洲综合影院红桃| 欧美久久久久久久久久| 麻豆乱码国产一区二区三区| 国产毛片一区| 在线性视频日韩欧美| 亚洲美女啪啪| 欧美极品一区| 最新日韩在线视频| 最新国产精品拍自在线播放| 久久综合九色| 麻豆九一精品爱看视频在线观看免费| 国产精品入口福利| 中国成人亚色综合网站| av成人动漫| 欧美日韩国产成人高清视频| 久久综合国产精品台湾中文娱乐网| 国产精品天天看| 亚洲一区二区欧美日韩| 亚洲综合第一页| 欧美日韩性视频在线| 亚洲大胆人体在线| 亚洲国产成人久久综合一区| 午夜精品免费视频| 欧美专区日韩视频| 国产视频自拍一区| 久久精彩免费视频| 久久综合九色99| 国内一区二区三区| 久久av老司机精品网站导航| 久久av红桃一区二区小说| 欧美午夜电影一区| 亚洲五月六月| 久久精品免费播放| 曰韩精品一区二区| 欧美成人日本| 一本色道久久综合亚洲精品婷婷 | 国产精品一区二区三区观看| 亚洲免费电影在线观看| 亚洲视屏一区| 国产精品中文在线| 午夜精品一区二区三区在线播放 | 亚洲欧美www| 亚洲欧美不卡| 国内精品久久久久久| 蜜臀久久久99精品久久久久久| 欧美激情2020午夜免费观看| 在线亚洲欧美视频| 国产综合色在线视频区| 欧美激情视频在线免费观看 欧美视频免费一| 欧美高清在线视频| 欧美亚洲在线| 日韩午夜在线电影| 国产日韩视频一区二区三区| 在线日韩欧美| 国产精品毛片a∨一区二区三区|国| 亚洲清纯自拍| 久久狠狠亚洲综合| 亚洲精品在线观| 国产裸体写真av一区二区| 免费观看国产成人| 亚洲欧美在线网| 亚洲精品美女91| 久久精品网址| 亚洲婷婷在线| 亚洲成色777777在线观看影院| 欧美午夜精品一区| 久久久欧美精品sm网站| 夜夜嗨网站十八久久| 欧美大片在线看免费观看| 亚洲欧美韩国| 亚洲国产精品传媒在线观看| 国产精品久久久久久超碰| 久久午夜精品| 国产精品99久久久久久久久| 免费在线看成人av| 香蕉久久夜色精品国产| 亚洲免费观看高清在线观看 | 久久国产精品电影| 一区二区三欧美| 亚洲高清一区二| 国产精品中文在线| 国产精品入口66mio| 久久成人免费电影|