上一條款我們說了,能以pass by reference to const 盡量不用pass by value。是不是所有的都要這樣呢?
這會使我們犯錯:開始傳遞一些reference指向其實並不存在的對象,這不是一件好事。
考慮一個用以表現有理數的class,內含一個函數用來計算兩個有理數的乘積。
classRational{
public:
Rational(intnumerator=0
intdenominator=-1);
...
private:
intn,d;
friendRationaloperator*(constRational&lhs,constRational&rhs);
};
這裡有版本是一個pass by value的。但是我們想能不能在函數返回時,pass by reference to const?
我們還知道,reference是一個已經存在的對象的引用。所以我們要建立一個對象,我們也知道建立一個對象可以在棧上,或堆上建立。以下版本是一個在棧上建立的。
constRational&operator*(constRational&lhs,constRational&rhs){
Rationalresult(lhs.n*rhs.n,lhs.d*rhs.d);
returnresult;
}
我們想在返回時,傳出一個引用。這個引用指向了棧中的result。問題出來了,當函數結束時,會調用Rational的解構函式,那麼result對象會被銷毀。那傳出去的reference是什麼呢。不知道~~~~
如果在棧上建立,不可以的話,我們是不是可以在堆上建立?下面的版本是在堆上建立。
constRational&operator*(constRational&lhs,constRational&rhs){
Rational*result =newRational(lhs.n*rhs.n,lhs.d*rhs.d);
returnresult;
}
現在的問題來了,我們依然要構造一個新對象。還不至如此,我們發現,我們new了,還沒有做delete呢。那在哪裡delete呢。我們沒有辦法~~~~~~~~~~
因此,考慮到這些,我們會想在堆和棧上都無法完成,如果我們在static上面呢?很好的想法,不過更加失敗。
constRational&operator*(constRational&lhs,constRational&rhs){
staticRationalresult;
result->n=lhs.n*rhs.n; result->d=lhs.d*rhs.d
returnresult;
}
就像所有用static對象的設計一樣,這一個也立刻會造成我們對多線程的安全性的疑慮。不過那些還是顯而易見的,如果想看更加深層次的,請看下面代碼:
booloperator==(constRatioal&lhs,constRational&rhs){
Rationala,b,c,d;
...
if((a*b)==(c*d)){
...
}else{
...
}
}
你猜怎麼樣?(a*b)==(c*d)全部都是true。
注意在operator==作用之前,先是兩個operator*起作用。還要注意每一次調用operator*都返回的是對一個static對象的引用。每一次調用的確也改變了static對象的值,但是由於是返回的reference,也就是指標。所以當兩次調用後,再調用operator==時,你就會發現所指同一個static東西,且相等。
請記住:
絕對不要返回pointer或reference指向一個local stack , 或 heap-allocated對象,或返回一個local static對象。