但是臨時(shí)變量在哪?
最后將臨時(shí)變量中的值賦值給ret
圖:
所有的傳值返回都會(huì)生成一個(gè)拷貝
便于理解,看一下匯編:
看第四句話,這里是說,把 eax 中的值,拷貝到 ret 中。
而再函數(shù)調(diào)用返回時(shí):
這里是將 c 的值放到 eax 中的。
這也就印證了返回時(shí),是以臨時(shí)拷貝形式返回的,由于返回值是 int ,所以是直接用的 eax 寄存器。
而不論這個(gè)函數(shù)結(jié)束后,返回的那個(gè)值會(huì)不會(huì)被銷毀,都會(huì)創(chuàng)建臨時(shí)變量返回,例如這段代碼 :
int fun()
{
static int n = 0;
n++;
return n;
}
int main()
{
int ret = fun();
cout << ret << endl;
return 0;
}
對(duì)于該函數(shù),編譯器仍然是創(chuàng)建臨時(shí)變量返回;因?yàn)榫幾g器不會(huì)對(duì)其進(jìn)行特殊處理。
看一下匯編:
仍然是放到 eax 寄存器中返回的。
埋個(gè)伏筆:你覺不覺的這個(gè)臨時(shí)變量創(chuàng)建的很冤枉,明明這塊空間一直存在,我卻依然創(chuàng)建臨時(shí)變量返回了?能不能幫它洗刷冤屈。
如果我改成引用返回會(huì)發(fā)生什么情況嗎?
int& add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int ret = add(1, 2);
cout << ret << endl;
return 0;
}
引用返回就是不生成臨時(shí)變量,直接返回 c 的引用。而這里產(chǎn)生的問題就是 非法訪問 。
造成的問題:
- 存在非法訪問,因?yàn)?add 的返回值是 c 的引用,所以 add 棧幀銷毀后,會(huì)訪問 c 位置空間,而這是讀操作,不一定檢查出來,但是本質(zhì)是錯(cuò)的。
- 如果 add 函數(shù)棧幀銷毀,空間被清理,那么取 c 值時(shí)取到的就是隨機(jī)值,取決于編譯器的決策。
ps:雖然vs銷毀棧幀沒有清理空間數(shù)據(jù),但是會(huì)二次覆蓋
來看個(gè)有意思的:
例如這里,當(dāng)調(diào)用 add 函數(shù)之后,返回 c 的引用,接收返回值是用的ret相當(dāng)于是 c 的引用,這時(shí)由于沒有清理?xiàng)瑪?shù)據(jù),所以打印3;
但是第二次調(diào)用,重新建立棧幀,由于棧幀大小相同,第二次建立棧幀可能還是在原位置,之前空間的數(shù)據(jù)被覆蓋,繼續(xù)運(yùn)算,但是此時(shí),ret 那塊空間的值就被修改了,而這時(shí)沒有接收返回值,但是原先的那塊 c 的值被修改,所以打印出來 ret 是 30 。
所以使用引用返回時(shí),一旦返回后,返回值的空間被修改,那么都可能會(huì)造成錯(cuò)誤,使用要小心!
引用返回有一個(gè)原則:如果函數(shù)返回時(shí),出了函數(shù)作用域,如果返回對(duì)象還在(還沒還給系統(tǒng)),則可以使用引用返回,如果已經(jīng)還給系統(tǒng)了,則必須使用傳值返回。
它倆的區(qū)別就是一個(gè)生成拷貝,一個(gè)不生成拷貝。
而這時(shí) static 修飾的靜態(tài)變量不委屈了:
int& fun()
{
static int n = 0;
n++;
return n;
}
因?yàn)?static 修飾的變量在靜態(tài)區(qū),出了作用域也存在,這時(shí)就可以引用返回。
我們可以理解引用返回也有一個(gè)返回值,但是這個(gè)返回值的類型是 int& ,中間并不產(chǎn)生拷貝,因?yàn)榉祷氐氖莿e名。這就相當(dāng)于返回的就是它本身。
有時(shí)引用返回可以發(fā)揮出意想不到的結(jié)果:
typedef struct Array
{
int a[N];
int size;
}AY;
int& PostAt(AY& ay, int i)
{
assert(i < N);
return ay.a[i];
}
int main()
{
AY ay;
PostAt(ay, 1);
// 修改返回值
for (int i = 0; i < N; i++)
{
PostAt(ay, i) = i * 3;
}
for (int i = 0; i < N; i++)
{
cout << PostAt(ay, i) << ' ';
}
return 0;
}
由于PostAt 的形參 ay 為 main 中 局部變量 ay的別名,所以 ay 一直存在;這時(shí)可以使用引用返回。
引用返回 減少了值拷貝 ,不比將其拷貝到臨時(shí)變量中返回;并且由于是引用返回,我們也可以 修改返回對(duì)象 。
總結(jié)提煉:如果出了作用域,返回變量(靜態(tài),全局,上一層棧幀,malloc等)仍然存在,則可以使用引用返回。
-
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7629瀏覽量
140123 -
C++
+關(guān)注
關(guān)注
22文章
2116瀏覽量
74725 -
面向?qū)ο?/span>
+關(guān)注
關(guān)注
0文章
64瀏覽量
10087
發(fā)布評(píng)論請(qǐng)先 登錄
諾基亞3G機(jī)2730c功能詳細(xì)解說
Visual C++教程之C++的基礎(chǔ)知識(shí)介紹

Visual C++教程之C++的語(yǔ)言資料概述免費(fèi)下載

C++程序設(shè)計(jì)教程之?dāng)?shù)據(jù)類型的詳細(xì)資料說明

C++程序設(shè)計(jì)教程之C++的初步知識(shí)的詳細(xì)資料說明

C++程序設(shè)計(jì)教程之?dāng)?shù)組的詳細(xì)資料說明

C++程序設(shè)計(jì)教程之指針的詳細(xì)資料說明

C++程序設(shè)計(jì)教程之C++工具的詳細(xì)資料說明

C++中的const和引用的討論
C++基礎(chǔ)語(yǔ)法中的引用、封裝和多態(tài)
c++引用詳細(xì)解說1

c++引用詳細(xì)解說2

c++引用詳細(xì)解說4

評(píng)論