c 返回變數和返回變數引用

2021-08-21 08:06:06 字數 4535 閱讀 2171

int&at()

int

at()

上面兩個函式,第乙個返回值是int的引用int&,第二個返回值是int,二者的區別是什麼呢?

我們先用乙個語句 const int& a = mymay.at();

來分別呼叫一次上面兩個函式,然後看組合語言的結果。

反彙編結果:

1 #int

& at()2#

5600bb6830

push

ebp

700bb6831

movebp,esp

800bb6833

subesp,0cch

900bb6839

push

ebx

1000bb683a

push

esi

1100bb683b

push

edi

1200bb683c

push

ecx

1300bb683d

leaedi,[ebp-0cch]

1400bb6843

movecx,33h

1500bb6848

moveax,0cccccccch

1600bb684d

rep stos dword ptr es:

[edi]

1700bb684f

popecx

1800bb6850

movdword ptr [this],ecx

19 m_data_++;

2000bb6853

moveax,dword ptr [this]

2100bb6856

movecx,dword ptr [eax]

2200bb6858

add ecx,1

2300bb685b

movedx,dword ptr [this]

2400bb685e

movdword ptr [edx],ecx

25 return m_data_;

26#取位址this中的值5879712(m_data_的位址)到暫存器eax中,此時暫存器eax存的是m_data_的位址

2700bb6860

moveax,dword ptr [this] 28}

2900bb6863

popedi

3000bb6864

popesi

3100bb6865

popebx

3200bb6866

movesp,ebp

3300bb6868

popebp

3400bb6869

ret35

3637

3839

40 const int& a = mymay.at();

4100176aa2

leaecx,[mymay]

4200176aa5

call

mymat:

:at (0171546h)

43 #此時暫存器eax中的值為m_data_的位址5879712,直接將位址5879712存入位址a中。

4400176aaa

movdword ptr [a],eax

45 cout << a << endl;

1 #int

at()2#

567012b6830

push

ebp

8012b6831

movebp,esp

9012b6833

subesp,0cch

10012b6839

push

ebx

11012b683a

push

esi

12012b683b

push

edi

13012b683c

push

ecx

14012b683d

leaedi,[ebp-0cch]

15012b6843

movecx,33h

16012b6848

moveax,0cccccccch

17012b684d

rep stos dword ptr es:

[edi]

18012b684f

popecx

19012b6850

movdword ptr [this],ecx

20 return m_data_;

21#和上面一樣,也是先取出m_data_的位址

22012b6853

moveax,dword ptr [this]

23 #和上面不一樣,不是直接將m_data_的位址放入暫存器eax中,而是取位址5879712中的值(m_data_=3)放入暫存器eax中,此時暫存器eax存的是m_data_的值(3)24

012b6856

moveax,dword ptr [eax] 25}

26012b6858

popedi

27012b6859

popesi

28012b685a

popebx

29012b685b

movesp,ebp

30012b685d

popebp

31012b685e

ret32

3334

3536

37 const int& a = mymay.at();

38008e6aa2

leaecx,[mymay]

39008e6aa5

call

mymat:

:at (08e154bh)

40#此時eax的值為3,將3存入位址ebp-24h中,

41008e6aaa

movdword ptr [ebp-24h],eax

42#將eax的值變成ebp-24h

43008e6aad

leaeax,[ebp-24h]

44#將位址ebp-24h寫到位址為a中,此時a代表的位址是ebp-24h

45008e6ab0

movdword ptr [a],eax

46 cout << a << endl;

所以結論就是:

1、返回值為引用型(int& )的時候,返回的是位址,因為這裡用的是 int& a=mymay.at();

,所以a和m_data_指的是同一塊位址(由暫存器eax傳回的5879712)。

2、返回值不是引用型(int)的時候,返回的是乙個數值。這個時候就很有意思了,編譯器是先將這個數值放入乙個記憶體中(上面例子中,該記憶體位址為ebp-24h),再把這個位址付給a,此時的a代表的位址是ebp-24h,和m_data_代表的位址不一樣(m_data_代表的位址是5879712)。

3、綜上兩點可以看出,當返回的值不是引用型時,編譯器會專門給返回值分配出一塊記憶體的(例子中為ebp-24h)。

看下面的函式,返回的是t而不是&t,所以一定會有臨時變數產生。

1

t function1()

5 t x=function1();

這裡的過程是:

1.建立命名物件t

2.拷貝構造乙個無名的臨時物件,並返回這個臨時物件

3.由臨時物件拷貝構造物件x

4.t x=function1();這句語句結束時,析構臨時物件

這裡一共生成了3個物件,乙個命名物件t,乙個臨時物件作為返回值,乙個命名物件x。

下面的函式稍微複雜一定,它沒有先定義乙個中間變數t,看起來似乎是直接返回了乙個臨時變數。但實際上,如果不經過c++的優化,那麼它並沒有提高效率,因為它還是建立了3個物件。

1

t function2()

4 t x=function2();

這裡的過程是:

1.建立乙個無名物件

2.由無名物件拷貝構造乙個無名的臨時物件

3.析構無名物件,返回臨時物件

4.由臨時物件拷貝構造物件x

5.t x=function2()語句結束時,析構臨時物件。

這裡一共生成了3個物件,其中有2個物件都是馬上被析構掉的,不能被後面的**使用。既然是這樣,那麼就會有優化的餘地,可以嘗試著不要前面的兩個臨時變數。c++確實會做這樣的優化,優化後的c++會避免匿名物件和臨時物件這兩個物件的生成,而直接生成x,這樣就減少了兩次物件生成-**的消耗,提高了程式效能。

其實function1()這段**也是會經過優化的,但因為臨時物件t是乙個命名物件,所以一定會被建立。儲存返回值的臨時物件是多餘的,會被優化掉而不生成。

但是,程式設計師不應該依賴這種優化,因為c++不保證這種優化一定會做。

C 返回物件和返回引用

最大的區別在於,返回物件的話會在記憶體中根據返回的型別開闢一塊區域,用返回的值對該記憶體進行初始化,如果是返回的物件,利用拷貝構造來初始化這個區域,但是這塊區域並沒有名字,就是說之後使用者沒辦法訪問到這個區域,也成為無名變數,它只能在接下來的 中進行一次性的用途,要不作為引數傳遞,或者將值列印,再之...

C 返回物件和返回引用

我們發現,在c 中,有些成員函式返回的是物件,而有些函式返回的又是引用。返回物件和返回引用的最主要的區別就是函式原型和函式頭。car run const car 返回物件 car run const car 返回引用 返回物件會涉及到生成返回物件的副本。因此,返回物件的時間成本包括了呼叫複製建構函式...

不能返回區域性變數的引用

源之 int add1 int a,int b int add2 int a,int b 請問這兩個函式返回有什麼區別,是乙個返回副本,另乙個直接返回嗎?呼叫函式add2有什麼危險嗎?add1的確返回了乙個副本,如果sum是自定義的類型別,可以很明顯看出拷貝建構函式在返回時被呼叫,對於內建型別沒什麼...