[原創(chuàng)文章歡迎轉(zhuǎn)載,但請(qǐng)保留作者信息]
Justin 于 2009-12-19
在認(rèn)真學(xué)習(xí)第20課后,大師有點(diǎn)擔(dān)心學(xué)生馬上變成傳引用(pass-by-reference)的粉絲。為了辯證的看待問(wèn)題,下一課現(xiàn)在開講……
初看題目,第21條玉律說(shuō)的也是一個(gè)很簡(jiǎn)單的情況:如果函數(shù)需要返回一個(gè)對(duì)象,就不要僅僅返回引用,因?yàn)榉祷氐囊糜锌赡芤呀?jīng)指向一個(gè)不存在的對(duì)象了。
沒錯(cuò),不過(guò)細(xì)讀下去發(fā)現(xiàn)還是有一些的細(xì)節(jié)自己原來(lái)并沒有考慮到。
如果函數(shù)返回的是值(對(duì)象),那么就難免要進(jìn)行創(chuàng)建對(duì)象操作(構(gòu)造/析構(gòu))來(lái)存儲(chǔ)返回的結(jié)果;如果是返回引用,就可以避免這額外的對(duì)象創(chuàng)建,節(jié)省了資源和時(shí)間。
看來(lái),似乎返回引用要優(yōu)于返回整個(gè)對(duì)象。
是這樣么?大師繼續(xù)揭開更本質(zhì)的一些東西:
如果一個(gè)函數(shù)可能返回一個(gè)對(duì)原來(lái)不存在的對(duì)象的引用,那么函數(shù)就要自己去創(chuàng)建這個(gè)對(duì)象:要么在棧上(stack)要么在堆上(heap)。
-
第一種情況中,函數(shù)中定義了局部對(duì)象,然后返回對(duì)該對(duì)象的引用。對(duì)象在函數(shù)結(jié)束后自動(dòng)銷毀,引用指向無(wú)效的地址。
OK,很簡(jiǎn)單。
-
第二種情況,函數(shù)使用new動(dòng)態(tài)創(chuàng)建了一個(gè)對(duì)象,然后返回對(duì)該對(duì)象的引用。粗看沒有問(wèn)題,因?yàn)檫@個(gè)返回的引用還是有效的。
但是細(xì)想就會(huì)發(fā)現(xiàn):我們能確保這個(gè)對(duì)象被正確的收回(delete)嗎?
書中舉了一個(gè)很好的例子:一個(gè)*運(yùn)算符函數(shù),接受兩個(gè)乘法運(yùn)算數(shù),返回一個(gè)積。
如果在函數(shù)中動(dòng)態(tài)創(chuàng)建一個(gè)對(duì)象來(lái)存儲(chǔ)乘積,并返回對(duì)這個(gè)新對(duì)象的引用,那么下面的計(jì)算就會(huì)帶來(lái)內(nèi)存泄漏:
??
Y=A*B*C
因?yàn)樵谶@個(gè)“連續(xù)”乘法中,有兩個(gè)“乘積對(duì)象”被創(chuàng)建,但是我們丟失了第一次乘法創(chuàng)建的對(duì)象的指針。
所以這樣的做法是不妥的。
也許大師有被問(wèn)過(guò):那么對(duì)于第一種情況我們可不可以返回一個(gè)靜態(tài)(static)對(duì)象的引用?書中用了同樣的例子來(lái)回答:NO。
?? if (A*B == C*D) {//..}
如果返回靜態(tài)對(duì)象的引用,上面的判斷語(yǔ)句永遠(yuǎn)得到true值,因?yàn)椤?=”號(hào)兩邊的運(yùn)算結(jié)果是指向同一塊數(shù)據(jù)的引用。
不知道是不是后面又有刨根問(wèn)題的學(xué)生追問(wèn):那我能不能用一個(gè)靜態(tài)對(duì)象的數(shù)組來(lái)存放不同此運(yùn)算的結(jié)果?大師懶得舉例子了,我猜想也沒必要:這樣的方案帶來(lái)的副作用及其開銷本身就已經(jīng)大于原來(lái)要解決的問(wèn)題了吧?
最后總結(jié)本課中心思想:
- 不要嘗試在函數(shù)中返回對(duì)局部對(duì)象(存儲(chǔ)于棧)的引用,也不要對(duì)動(dòng)態(tài)創(chuàng)建的對(duì)象(存儲(chǔ)于堆)做同樣的蠢事,而如果真有打算、非??释?、十分想要返回對(duì)靜態(tài)對(duì)象的引用,在這么做之前也要考慮清楚會(huì)不會(huì)有上面例子中的情況出現(xiàn)。
- 至少,返回對(duì)象不會(huì)有上面列出的種種錯(cuò)誤危險(xiǎn),僅僅是有可能帶來(lái)創(chuàng)建額外對(duì)象的開銷而已,而這個(gè)開銷的可能還有可能被排除,如果你用的編譯器足夠聰明的話。
下課!
謝~謝~老~師~