轉自:
https://blog.csdn.net/qq_22660775/article/details/89854545
返回引用與返回非引用的區別:
返回引用時,函數內部不會構造一個臨時變量,而是直接將返回值返回出去。而當為非引用時,會構造一個臨時變量(但不一定),然后返回這個匿名的臨時變量。
舉例:
class B {
public:
B(){
cout << "B的構造函數" << endl;
}
B(int i){
cout << "帶int型參數的B的構造函數" << endl;
}
B(const B &ano){
cout << "B的拷貝構造函數" << endl;
}
B& operator=(const B& rhs){
cout << "B的賦值操作符" << endl;
return *this;
}
virtual ~B(){
cout << "B的析構函數" << endl;
}
};
B func2()
{
B b;
return b;
}
int main() {
B t;
t=func2();
//B z=func2();
cout<<endl;
}
結果為:

實際上這個過程是:
首先在main中生成t,調用一個默認構造函數
然后在func2()中生成一個b,調用一個默認構造函數
然后要返回b了,使用拷貝構造,利用b拷貝構造一個臨時變量tmp
然后析構b
然后利用tmp賦值給t
最后析構這個臨時變量tmp
可以看到,整個過程,由於使用的是非引用,因此會首先調用拷貝構造構造臨時變量tmp,然后返回這個tmp
而當調用B z=func2()時:

首先進入func2,對b進行構造
但這里沒有構造臨時變量,由於外面是B z=func2(),實際上是直接將這個z傳入,然后利用b來拷貝構造這個z,最后再析構b
注意這里析構的順序,在上面看到,構造完臨時變量tmp后,b直接就析構了,然后tmp賦值給t后tmp才析構。注意這里b的析構時間和上一行的析構時間:
上一行是利用b構造完z后b才析構,也就是說實際上是將這個z當做tmp來拷貝構造。
而最前面是先拷貝構造tmp,然后b馬上析構,最后用tmp來給b賦值。
也就是說:
如果返回的是非引用,並不一定會構造一個臨時變量。
如果使用B z=func2()這種方式是不會生成臨時變量的;但B b;b=func2();是會生成臨時變量的。
想到上次去網易面試時考官問我的一個問題:
這個返回的ans怎么提高效率?
如果用引用返回的話則會出問題,因為返回的是局部對象,在賦值的時候實際上已經析構了。
當時的回答是將結果作為參數放入func()中,也就是改寫為void func(vector<int>& result);然后這樣就可以提高效率
但面試官應該想讓我get到另外的點
難道是移動語義或者完美轉發?這個我還沒看,需要好好研究下。
vector<int> func()
{
vector<int> ans(2,1);
return ans;
}
