預設情況下c++是以值傳遞的形式傳遞物件到函式的。除非特別指定,否則函式引數都是以實際實參的副本為初值。呼叫端所獲的也是函式返回值的乙個副本。這些副本是由物件的拷貝建構函式產生,這會使值傳遞非常費時。
特別是在乙個結構複雜的類中,例如:
class student : public person
當有以下函式:
bool validatestudent(student s);
student plato;
bool platoisok=validatestudent(plato);
即以置傳遞方式傳遞乙個student物件時,會導致呼叫一次person拷貝建構函式,一次student拷貝建構函式,string類拷貝建構函式,當函式內的student副本被銷毀時,每乙個建構函式地呼叫都需要乙個對應的析構函式呼叫動作。
所以可以將值傳遞方式的函式進行優化,如下
bool validatestudent(student s);// 優化前
bool validatestudent(const student &s);// 優化後
這樣的話效率將大大提高。
不僅如此,通過引用傳遞可以避免派生類被視作乙個基類的情況(因為派生類通過基類的拷貝建構函式建立了乙個只有基類屬性的副本)。
但是並不是任何時候使用引用傳遞都會比使用值傳遞效率高,因為引用傳遞往往意味著傳遞指標,所以如果引數是內建型別的話,通過值傳遞會比引用傳遞效率高。
在stl的迭代器與函式物件中,使用值傳遞效率也會比引用傳遞高,因為習慣上他們都被設計為值傳遞。
總結:函式建立物件的方法有兩個:在stack空間或在heap空間建立。如果定義乙個區域性變數,就是在stack空間建立物件1)盡量以引用傳遞代替值傳遞,前者往往效率更高,並可以避免切割問題。
2)這個規則並不適用於內建型別、以及stl的迭代器和函式物件。對他們而言,值傳遞效率更高。
const rational& operator*(const rational& lhs,const rational& rhs)
這個函式返回乙個指向result的引用,但result是乙個區域性物件,而區域性物件在函式退出之前就被銷毀了。
如果在堆內構造乙個物件,並返回引用指向它,堆物件由new建立
const rational& operator* (const rational& lhs,const rational&rhs)
因為函式中使用了new,也就需要delete,但是其中並沒有實施delete的操作,會導致資源洩露
上面的操作都是因為對返回的結果呼叫了建構函式而受到懲罰,如果不呼叫建構函式呢?
如果讓返回的引用指向乙個被定義於函式內部的static rational 物件(不會呼叫建構函式了)
const raional& operator*(const rational& lhs,const rational&rhs)
bool operator==(const rational&lhs,const rational&rhs);
rational a,b,c,d;
....
if((a*b)==(c*d))
else
結果就是,表示式((a*b)==(c*d))總是被核算為true,不論a,b,c,d,的值是什麼。
將**重寫拆開迷霧:if(operator==(operator*(a,b) operator*(c,d)))
因為在operator==呼叫之前已經有l兩個operator*起作用,每乙個都返回引用指向operator*內部定義的static rational 物件。
雖然兩次operator*呼叫的確各自改變了static rational 物件值,但由於他們返回的都是引用,因此呼叫端看到的永遠都是static rational 的現值。
總結:絕不要返回乙個指向區域性物件的指標或者引用,或乙個指向堆物件的引用,或返回指向乙個有可能同時需要多個這樣物件的區域性靜態物件的指標或引用。
設計與宣告
條款18 讓介面容易被正確使用,不易被誤用 條款19 設計class猶如設計type 條款20 寧以pass by value to const替換pass by value 預設情況下c 以by value方法給物件傳遞引數,函式引數都是物件的副本,這些副本是由物件的copy建構函式產出,這可能使...
設計與宣告(一)
條款18 讓介面容易被正確使用,不易被誤用 開發乙個 容易被正確使用,不易被誤用 的介面,首先必須考慮使用者會做出什麼樣的錯誤。以下為例 class date 乍見之下這個介面通情達理,但是至少容易犯兩個錯誤。第一,他們可能以錯誤的次序傳遞引數 第二,他們可能傳遞乙個無效的引數。許多客戶端錯誤可以因...
二 設計與宣告
類的設計是一件非常複雜的事情,設計師在設計類的時候不僅僅要考慮實現的功能,又要兼顧擴充套件性 易用性等一些功能外的特性。在使用外部庫的時候,在不查閱文件的基礎上,我們常常煩惱於如何呼叫api,一些引數非常容易混淆。舉乙個例子我們在學生系統中要對一名學生進行輸入生日的操作。item19常常我們使用a ...