一、 引用
1.1 引用概念
引用(reference)是為變量起了另一個名字,而不是定義一個新變量。編譯器不會為引用變量開辟內存空間,它和它引用的變量共用同一塊內存空間。其使用形式如下:
類型& 引用變量名(對象名) = 引用實體;
eg:
int ival = 1024;
int &refVal = ival; // refVal 指向ival(是ival的另一個名字)
int &refVal2; // 報錯:引用必須被初始化
定義引用時,程序把引用和它的初始化綁定在一起,而不是將初始值拷貝給引用。一旦初始化完成,引用將和它的初始值對象一直綁定在一起。因為無法令引用重新綁定到另外一個對象,所以引用必須初始化。注意:引用類型必須和引用實體是同種類型的。
1.2 引用的特性
(1) 引用在定義式必須初始化;
(2)一個變量可以有多個引用;
(3)引用一旦引用一個實體,再不能引用其他實體;
1.3 引用的使用場景
1 做參數
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
2 做返回值
int& Count()
{
static int n = 0;
n++;
// ...
return n;
}
注意:如果函數返回時,出了函數作用域,如果返回對象還未還給系統,則可以使用引用返回,如果已經還給系統了,則必須使用傳值返回。
例如下面代碼就會出現問題。
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);
Add(3, 4);
cout << "Add(1, 2) is :" << ret << endl;
system("pause");
return 0;
}
運行結果:
Add(1, 2) is :7
請按任意鍵繼續. . .
所以使用時注意作用域。
二、 傳值和傳引用的效率對比
先用以下代碼進行測試一下:
#include <time.h>
#include <iostream>
using namespace std;
struct A { int a[10000]; };
void TestFunc1(A a) {} // 傳值
void TestFunc2(A& a) {} // 傳引用
A a;
A Fun3() {
return a;
}
A &Fun4() {
return a;
}
void test1()
{
A a;
// 以值作為函數參數
size_t begin1 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc1(a);
size_t end1 = clock();
// 以引用作為函數參數
size_t begin2 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc2(a);
size_t end2 = clock();
// 分別計算兩個函數運行結束后的時間
cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
// 以值作為函數返回值
size_t begin3 = clock();
for (size_t i = 0; i < 100000; ++i)
Fun3();
size_t end3 = clock();
// 以引用作為函數返回值
size_t begin4 = clock();
for (size_t i = 0; i < 100000; ++i)
Fun4();
size_t end4 = clock();
// 分別計算兩個函數運行結束后的時間
cout << "Fun3 time:" << end3 - begin3 << endl;
cout << "Fun4 time:" << end4 - begin4 << endl;
}
int main()
{
test1();
system("pause");
return 0;
}
運行結果:
TestFunc1(A)-time:129 <-- 參數傳值
TestFunc2(A&)-time:2 <-- 參數傳引用
Fun3 time:336 <-- 返回值為值
Fun4 time:2 <-- 返回值為引用
請按任意鍵繼續. . .
從運行結果可見傳引用比傳值的效率高很多。因為,以值做為參數或者返回值類型,在傳參和返回期間,函數不會直接傳遞實參或者將變量本身直接返回,而是傳遞實參或者返回變量的一份臨時的拷貝,因此用值作為參數或者返回值類型,效率是非常低下的,尤其是當參數或者返回值類型非常大時,效率就更低。
三、 引用和指針的區別
在語法概念上引用就是一個別名,沒有獨立空間,和其引用實體共用同一塊空間。但是在底層實現上,引用是按指針的方式實現的。怎么體現呢,看匯編代碼。如下:
int main()
{
int a = 10;
int& ra = a;
ra = 20;
int* pa = &a;
*pa = 20;
return 0;
}
將上面簡單代碼進行反匯編:
可見:
在底層實現上:引用通過指針實現,定義一個引用類型變量相當於定義一個指針類型變量
語法上: 引用是別名,不是指針,沒有發生拷貝。
引用和指針的不同點:
1. 引用在定義時必須初始化,指針沒有要求
2. 引用在初始化時引用一個實體后,就不能再引用其他實體,而指針可以在任何時候指向任何一個同類型實體
3. 沒有NULL引用,但有NULL指針
4. 在sizeof中含義不同:引用結果為引用類型的大小,但指針始終是地址空間所占字節個數(32位平台下占4個字節)
5. 引用自加即引用的實體增加1,指針自加即指針向后偏移一個類型的大小
6. 有多級指針,但是沒有多級引用
7. 訪問實體方式不同,指針需要顯式解引用,引用編譯器自己處理
8. 引用比指針使用起來相對更安全
————————————————
版權聲明:本文為CSDN博主「尼克選手」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_44132627/article/details/106356423
