1. 程式人生 > >effective c++條款20:寧以pass-by-reference-to-const替換pass-by-value

effective c++條款20:寧以pass-by-reference-to-const替換pass-by-value

1. 更高效

考慮如下的一個base class和derived class:

class Base
{
private:
    std::string name;
    std::string address;
public:
    Base(){}
    ~Base(){}

};
class Derived:public Base
{
public:
    Derived(){}
    ~Derived(){}
};

如果存在一個函式需要以一個Derived物件為引數,而你以pass-by-value方式傳遞:

void Fun(Derived w);
Derived h;
Fun(h);

我們都知道,以pass-by-value方式傳遞引數就是構造一個原引數的一個副本,那麼Fun函式構造一個derived物件的成本為:

Derived的構造+Base的構造+name的構造+address的構造;

在函式結束後,還需要Derivede的析構+Base的析構+name的析構+address的析構;

而對pass-by-reference-to-const需要的成本:

一個指標(傳引用的底層實現往往是指標)。

很明顯,pass-by-reference-to-const比pass-by-value更高效。

2. 避免物件切割

#include<iostream>
using namespace std;
class Base
{
public:
    Base(){}
    ~Base(){}
public:
    virtual void Show() const 
    {
        cout << "Base" << endl;
    }
};
class Derived:public Base
{
public:
    Derived(){}
    ~Derived(){}
public:
    void Show() const
    {
        cout << "Derived" << endl;
    }
};
void Fun(Base w)
{
    w.Show();
}
void Fun1(const Base &w)
{
	w.Show();
}
int main()
{
    Derived Ob;
    Fun(Ob);
    Fun1(Ob);
    return 0;
}

執行結果:

可以發現,如果以pass-by-value方式傳遞引數,那麼Fun函式會以Base Class的建構函式建立一個物件副本,而以pass-by-reference-to-const方式傳遞引數,Fun1函式會保持原有的型別。

3. 內建型別、STL的迭代器和函式物件並不一定適合pass-by-reference-to-const方式

因為pass-by-reference-to-const往往以指標方式實現,所以如果你要傳遞的引數為一個內建型別,那麼pass-by-value方式往往是一個更高效的選擇。

對於STL迭代器和函式物件,習慣上他們都被設計為pass-by-value方式,所以pass-by-value方式往往是一個更高效的選擇。

對於許多STL容器,雖然大小隻比一個指標大一點點,但是複製STL容器就意味著複製內部指標所指向的所有東西,代價非常昂貴。

對於很小自定義物件,他們以後可能被修改,變得越來越大,所以以“物件體積大小來衡量以哪種方式傳遞”是一個不可靠的推論。

結論:

儘量以pass-by-reference-to-const方式替換pass-by-value方式,前者往往更高效並且可以避免切割問題。

以上結論並不適用於函式物件,STL迭代器以及內建型別,他們往往以pass-by-value方式更高效。