Effective c++ 條款20:寧以pass-by-reference-to-const替換pass-by-value
1、預設情況下c++以by value方式傳遞物件至(或來自)函式
除非你另外指定,否則函式引數都是以實際實參的復件(副本)為初值,而呼叫端所獲得的也是函式返回值的一個復件。這些復件由物件的copy建構函式產出,這也可能使得pass-by-value成為昂貴的操作。
class Person {
public:
Person();
virtual ~Person();
...
private:
std::string name;
std::string address;
};
class Student: public Person {
public:
Student();
virtual ~Student();
...
private:
std::string schoolName;
std::string schoolAddress;
};
現在考慮以下程式碼,其中呼叫函式validateStudent,後者需要一個Student實參並返回它是否有效。
bool validateStudent(Student s);
Student plato;
bool platoIsOk = validateStudent(plato);
當上述函式被呼叫時,無疑Student的copy建構函式會被銷燬,以plato為藍本將s初始化。同樣,當validateStudent返回s會被銷燬。因此對於此函式而言,引數的傳遞成本是“一次Student copy建構函式呼叫,加上一次Student解構函式呼叫”。
而Student物件內有兩個string物件,所以每次構造Student也就構造了兩個string物件,此外Student物件繼承自Person物件,所以每次構造Student物件也必須構造出一個Person物件,加上Person物件內的string成員,因此總體成本是“六次建構函式和六次解構函式”!
2、以pass-by-reference-to-const方式傳參
bool validateStudent(const Student& s);
這種傳遞方式的效率高得多:沒有任何建構函式或解構函式被呼叫。以reference的 方式傳遞沒有任何新物件被建立,將形參宣告為const可以防止實參被改變,而且以reference方式傳遞可以避免slicing(物件切割)問題。當一個derived class物件以by value方式傳遞並視為一個base class物件,base class的copy建構函式會被呼叫,而“造成此物件的行為像個derived class物件”的那些特化性質全被切割掉了。解決切割問題的方法就是以by reference-to-const方式傳遞引數,因為references往往以指標實現出來,因此pass-by-reference通常意味真正傳遞的是指標。然而如果你有個物件屬於內建型別
,比如int,pass-by-value往往比pass-by-reference的效率高些。這個忠告也適用於STL的迭代器和函式物件。