6、效率比較
值和引用的作為返回值類型的性能比較:
struct A { int a[10000]; };
A a;
// 值返回
A TestFunc1() { return a; } // 拷貝
// 引用返回
A& TestFunc2() { return a; } // 不拷貝
void TestReturnByRefOrValue()
{
// 以值作為函數的返回值類型
size_t begin1 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc1();
size_t end1 = clock();
// 以引用作為函數的返回值類型
size_t begin2 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc2();
size_t end2 = clock();
// 計算兩個函數運算完成之后的時間
cout << "TestFunc1 time:" << end1 - begin1 << endl;
cout << "TestFunc2 time:" << end2 - begin2 << endl;
}
int main()
{
TestReturnByRefOrValue();
return 0;
}
由于傳值返回要拷貝,所以當拷貝量大,次數多時,比較耗費時間;而傳引用返回就不會,因為返回的就是別名。
對于返回函數作用域還在的情況,引用返回優先。
引用傳參和傳值傳參效率比較 :
struct A { int a[10000]; };
void TestFunc1(A a) {}
void TestFunc2(A& a) {}
void TestRefAndValue()
{
A a;
// 以值作為函數參數
size_t begin1 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc1(a);
size_t end1 = clock();
// 以引用作為函數參數
size_t begin2 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc2(a);
size_t end2 = clock();
// 分別計算兩個函數運行結束后的時間
cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}
int main()
{
TestRefAndValue();
}
還是引用快,因為引用減少拷貝次數:
總結:引用的作用主要體現在傳參和傳返回值
- 引用傳參和傳返回值,在有些場景下可以提高性能(大對象 and 深拷貝對象 – 之后會講)。
- 引用傳參和傳返回值,在對于輸出型參數和輸出型返回值很舒服。說人話就是形參改變,實參也改變 or 返回對象(返回值改變)。
7、常引用
const 修飾的是常變量,不可修改。
a本身都不能修改,b為a的引用,那么b也不可以修改,這樣就沒意義了。a是只讀,但是引用b具有可讀可寫的權利,該情況為權限放大,所以錯誤了。
這時,只要加 const 修飾 b ,讓 b 的權限也只有只讀,使得 權限不變 ,就沒問題了:
而如果原先變量可讀可寫,但是別名用 const 修飾,也是可以的,這種情況為 權限縮小 :
對于函數的返回值來說,也不能權限放大,例如:
int fun()
{
static int n = 0;
n++;
return n;
}
int main()
{
int& ret = fun(); // error
return 0;
}
這樣也是不行的,因為返回方式為 傳值返回 ,返回的是臨時變量,具有 常性 ,是不可改的;而引用放大了權限,所以是錯誤的;這時加 const 修飾就沒問題:
const int& ret = c(1, 2)
那么這種情況為什么不可以?
而這樣就可以了?
因為類型轉換會產生臨時變量 :
對于類型轉換來說,在轉換的過程中會產生一個個臨時變量,例如 double d = i,把i轉換后的值放到臨時變量中,把臨時變量給接收的值d
而臨時變量具有常性,不可修改,引用就加了寫權限,就錯了,因為 權限被放大了 。
小結:對于引用,引用后的變量所具權限可以縮小或不變,但是不能放大(指針也適用這個說法)
作用 :在一些場景下,假設 x 是一個大對象,或者是深拷貝對象,那一般都會用引用傳參,減少拷貝,如果函數中不改變 x ,盡量用 const 引用傳參。
這樣可以防止 x 被修改 ,而對于 const int& x 也可以接受權限對等或縮小的對象,甚至為常量:
結論 :const type& 可以接收各種類型的對象(變量、常量、隱式轉換)。對于輸出型參數用引用,否則用 const type&,更加安全。
8、指針和引用區別
從語法概念上來說,引用是沒有開辟空間的,而指針是開辟了空間的,但是從底層實現上來說,則又不一樣:
int main()
{
int a = 10;
int& ra = a;
ra = 20;
int* pa = &a;
*pa = 20;
return 0;
}
匯編:
lea 是取地址:我們發現無論引用和指針,都會取地址,且這些過程和指針一樣。
其實從匯編上,引用其實是開空間的,并且實現方式和指針一樣,引用其實也是用指針實現的。
區別匯總:
- 引用概念上定義一個變量的 別名 ,指針存儲一個變量 地址。
- 引用 在定義時 必須初始化 ,指針最好初始化 ,但是不初始化也不會報錯。
- 引用在初始化時引用一個實體后 ,就不能再引用其他實體 ,而指針可以在任何時候指向任何一個同類型。
- 沒有NULL引用,但有NULL指針。
- 在sizeof中含義不同:引用結果為 引用類型的大小,但指針始終是 地址空間所占字節個數 (32位平臺下占4個字節)。
- 引用自加即引用的實體增加1,指針自加即指針向后偏移一個類型的大小。
- 有多級指針,但是沒有多級引用。
- 訪問實體方式不同,指針需要顯式解引用,引用編譯器自己處理。
- 引用比指針使用起來相對更安全。
以上全部是對c++引用的一個詳細解讀,希望大家受益良多哈。平時在寫代碼的時候多調試看看里面的原理,看看編譯器到底是怎么進行運行的,讓自己對編碼這塊更具有靈性!
-
C語言
+關注
關注
180文章
7614瀏覽量
137477 -
C++
+關注
關注
22文章
2114瀏覽量
73805 -
面向對象
+關注
關注
0文章
64瀏覽量
9999
發布評論請先 登錄
相關推薦
評論