[英]Passing constructor arguments by value or by reference
只是一個關於這樣的函數的快速問題:
class Test {
public:
Test(vector<int>& v) {
v_ = v;
}
private:
std::vector<int> v_;
};
使用Test(vector<int>& v)
和Test(vector<int> v)
之間有什么區別? 我似乎知道第一個應該更快,因為它是傳遞參考。 但我不確定是否存在其他差異。
不同之處在於使用Test(vector<int>& v)
(其中BTW是左值引用)v指的是原始對象,而使用Test(vector<int> v)
則有副本。 下面的示例代碼演示了int
和普通函數的區別(請注意,對於int
,pass-by-value實際上更快!):
#include <iostream>
int global_i;
void pass_by_value(int i)
{
std::cout << "pass by value:\n";
std::cout << "initially: i = " << i << ", global_i = " << global_i << "\n";
i++;
std::cout << "after i++: i = " << i << ", global_i = " << global_i << "\n";
global_i++;
std::cout << "after global_i++: i = " << i << ", global_i = " << global_i << "\n";
}
void pass_by_reference(int& i)
{
std::cout << "pass by reference:\n";
std::cout << "initially: i = " << i << ", global_i = " << global_i << "\n";
i++;
std::cout << "after i++: i = " << i << ", global_i = " << global_i << "\n";
global_i++;
std::cout << "after global_i++: i = " << i << ", global_i = " << global_i << "\n";
}
void pass_by_const_reference(int const& i)
{
std::cout << "pass by const reference:\n";
std::cout << "initially: i = " << i << ", global_i = " << global_i << "\n";
// i++; not allowed!
// std::cout << "after i++: i = " << i << ", global_i = " << global_i << "\n";
global_i++;
std::cout << "after global_i++: i = " << i << ", global_i = " << global_i << "\n";
}
int main()
{
global_i = 1;
pass_by_value(global_i);
global_i = 1;
pass_by_reference(global_i);
global_i = 1;
pass_by_const_reference(global_i);
}
這個輸出是:
pass by value:
initially: i = 1, global_i = 1
after i++: i = 2, global_i = 1
after global_i++: i = 2, global_i = 2
pass by reference:
initially: i = 1, global_i = 1
after i++: i = 2, global_i = 2
after global_i++: i = 3, global_i = 3
pass by const reference:
initially: i = 1, global_i = 1
after global_i++: i = 2, global_i = 2
如您所見,通過按值調用,參數和傳遞的變量是完全獨立的。 遞增參數不會更改傳遞的變量,並且遞增傳遞的變量不會更改參數。 另一方面,通過引用傳遞,參數只允許訪問傳遞的變量:無論你增加哪一個都無關緊要,因為它們是相同的。 通過const引用傳遞,它們也是相同的,但是你不允許使用這個參數(盡管有這種方法)。 但是,該參數仍然反映了對傳遞的變量的任何更改。
這些是功能上的差異。 但是有一些差異:對於傳遞值和傳遞const引用,您可以使用rvalue,如call_by_value(2)
或call_by_const_reference(2)
。 對於按值調用,很明顯會發生什么:參數得到值2,就是這樣。 但是對於const引用,有一個期望的對象(例如,你可以在函數中獲取該對象的地址)。 因此,在這種情況下,創建臨時對象。 對於非const引用的調用,您不能傳遞右值。
C ++ 11在混合中添加了另一種類型,即右值引用。 這些用&&
代替&
表示。 在函數內部,它們的行為與普通(左值)引用完全相同,但它們的區別在於它們可以綁定到右值,即使它們不是常量。 此外,如果您將它們用作返回類型,則調用表達式將為rvalue類型,就像您返回了一個值一樣。 特別是,您將無法傳遞函數的結果,該函數將rvalue引用返回到期望左值引用的函數,就像您不能使用文字2那樣。
您的代碼中沒有右值引用,只需要進行大量不必要的復制。
但是,既然我們正在談論這個話題,那么這是用移動語義編寫它的正確方法:
Test(std::vector<int> v) // by value!
: v_(std::move(v))
{
}
在11之前的世界中,下一個最好的方法是通過const-reference獲取參數並復制它:
Test(std::vector<int> const & v)
: v_(v)
{
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.