effective C++ 条款 21:必须返回对象时别妄想返回其reference
考慮有理數(shù)的class:
class Rational
{
public:
??? Rational(int numerator = 0, int denominator = 1);
protected:
private:
??? int n, d;
??? friend Rational operator*(const Rational& lhs, const Rational& rhs);
};
by value版的operator*, 你可能想改而返回reference,以根除pass-by-value的種種邪惡,省掉構(gòu)造和析構(gòu),但是,
所謂reference只是個名稱,代表某個既有對象,任何時候看到一個reference聲明式,你都應(yīng)該立刻問自己,它的另一個名稱是什么?
如果operator*要返回一個reference指向如此數(shù)值,他必須自己創(chuàng)建那個Rational對象。
const Rational& operator*(const Rational& lhs, const Rational& rhs)
{
??? Rational result(lhs.n * rhs.n, lhs.d * rhs.d); //警告!糟糕的代碼!
??? return result;
}
你的目標(biāo)是要避免調(diào)用構(gòu)造函數(shù),而result卻必須像任何對象一樣地由構(gòu)造函數(shù)構(gòu)造起來。更嚴(yán)重的是result是一個local對象,而local對象在函數(shù)退出前被銷毀了。因此這個返回的reference指向的是一個“從前的”Rational;如今已經(jīng)被銷毀了。任何調(diào)用者甚至對此函數(shù)的返回值做任何一點(diǎn)點(diǎn)運(yùn)用,都會陷入“無定義行為”的惡地。
于是考慮在heap內(nèi)構(gòu)造一個對象, 并返回reference指向它。
const Rational& operator*(const Rational& lhs, const Rational& rhs)
{
??? Rational* result = new Rational(lhs.n * rhs.n, lhs.d * rhs.d); //更糟的代碼!
??? return *result;
}
你還是必須付出一個構(gòu)造函數(shù)調(diào)用的代價,此外又有另一個問題:誰該對著被你new出來的對象實(shí)施delete?
Rational w, x, y, z;
w = x * y * z; //與operator*(operator*(x, y), z)相同
同一個語句調(diào)用了兩次operator*, 因而兩次使用new,也就需要兩次delete。但卻沒有合理的辦法讓operator*使用者進(jìn)行delete調(diào)用, 因?yàn)闆]有合理的辦法讓他們?nèi)〉給perator*返回的reference背后隱藏的那個指針。這絕對導(dǎo)致資源泄漏。
或許你想到一種辦法可以避免任何構(gòu)造函數(shù)被調(diào)用。“讓operator*返回reference指向一個被定義于函數(shù)內(nèi)部的static Rational對象”
const Rational& operator*(const Rational& lhs, const Rational& rhs)
{
??? static Rational result; //又是一堆爛代碼。
??? result = ...; //lhs*rhs
??? return result;
}
就像所有用上static對象的設(shè)計一樣, 這個也立刻造成我們對多線程安全性的疑慮。只是顯而易見的弱點(diǎn)。更深層的瑕疵:
bool operator=(const Rational& lhs, const Rational& rhs);
Rational a, b, c, d;
if ((a*b) == (c*d)){
??? ...
}else{
??? ...
}
表達(dá)式if ((a*b) == (c*d))總是被核算為true, 不論a,b, c,d是什么。
在operator==被調(diào)用前,已有兩個operator*調(diào)用式起作用,每個都返回operator*內(nèi)部定義的static Rational對象的reference,這個將“operator*內(nèi)的static Rational對象值”和“operator*內(nèi)的static Rational對象值”比較,不相等才怪。(雖然兩次調(diào)用operator*都改變了static Rational對象的值, 但是返回的reference, 調(diào)用端看到的永遠(yuǎn)是static Rational的現(xiàn)值)。
一個“必須返回新對象”的函數(shù)的正確寫法:就讓那個函數(shù)返回一個新對象。
inline const Rational operator*(const Rationa& lhs, const Rational& rhs)
{
??? return Rational(lhs.n * rhs.n, lhs.d * rhs.d);
}
絕不要返回pointer或reference指向一個local stack對象, 或返回reference指向一個heap-allocated對象, 或返回pointer或reference指向一個local static對象而有可能同時需要多個這樣的對象。條款4已經(jīng)為“在單線程環(huán)境中合理返回reference指向一個local static對象”提供了一份設(shè)計實(shí)例(singleton)
轉(zhuǎn)載于:https://www.cnblogs.com/lidan/archive/2012/01/17/2325108.html
總結(jié)
以上是生活随笔為你收集整理的effective C++ 条款 21:必须返回对象时别妄想返回其reference的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 迷失在小镇上的日记(16)
- 下一篇: QT基础二