int& at() { return m_data_; }
int at() { return m_data_; }
上面兩個函數,第一個返回值是int的引用int&,第二個返回值是int,兩者的區別是什麼呢?html
咱們先用一個語句 const int& a = mymay.at(); 來分別調用一次上面兩個函數,而後看彙編語言的結果。c++
反彙編結果:程序員
1 #int& at() 2 #{ 3 # return m_data_; 4 #} 5 6 00BB6830 push ebp 7 00BB6831 mov ebp,esp 8 00BB6833 sub esp,0CCh 9 00BB6839 push ebx 10 00BB683A push esi 11 00BB683B push edi 12 00BB683C push ecx 13 00BB683D lea edi,[ebp-0CCh] 14 00BB6843 mov ecx,33h 15 00BB6848 mov eax,0CCCCCCCCh 16 00BB684D rep stos dword ptr es:[edi] 17 00BB684F pop ecx 18 00BB6850 mov dword ptr [this],ecx 19 m_data_++; 20 00BB6853 mov eax,dword ptr [this] 21 00BB6856 mov ecx,dword ptr [eax] 22 00BB6858 add ecx,1 23 00BB685B mov edx,dword ptr [this] 24 00BB685E mov dword ptr [edx],ecx 25 return m_data_; 26 #取地址this中的值5879712(m_data_的地址)到寄存器eax中,此時寄存器eax存的是m_data_的地址 27 00BB6860 mov eax,dword ptr [this] 28 } 29 00BB6863 pop edi 30 00BB6864 pop esi 31 00BB6865 pop ebx 32 00BB6866 mov esp,ebp 33 00BB6868 pop ebp 34 00BB6869 ret 35 36 37 38 39 40 const int& a = mymay.at(); 41 00176AA2 lea ecx,[mymay] 42 00176AA5 call MyMat::at (0171546h) 43 #此時寄存器eax中的值爲m_data_的地址5879712,直接將地址5879712存入地址a中。 44 00176AAA mov dword ptr [a],eax 45 cout << a << endl;
1 #int at() 2 #{ 3 # return m_data_; 4 #} 5 6 7 012B6830 push ebp 8 012B6831 mov ebp,esp 9 012B6833 sub esp,0CCh 10 012B6839 push ebx 11 012B683A push esi 12 012B683B push edi 13 012B683C push ecx 14 012B683D lea edi,[ebp-0CCh] 15 012B6843 mov ecx,33h 16 012B6848 mov eax,0CCCCCCCCh 17 012B684D rep stos dword ptr es:[edi] 18 012B684F pop ecx 19 012B6850 mov dword ptr [this],ecx 20 return m_data_; 21 #和上面同樣,也是先取出m_data_的地址 22 012B6853 mov eax,dword ptr [this] 23 #和上面不同,不是直接將m_data_的地址放入寄存器eax中,而是取地址5879712中的值(m_data_=3)放入寄存器eax中,此時寄存器eax存的是m_data_的值(3) 24 012B6856 mov eax,dword ptr [eax] 25 } 26 012B6858 pop edi 27 012B6859 pop esi 28 012B685A pop ebx 29 012B685B mov esp,ebp 30 012B685D pop ebp 31 012B685E ret 32 33 34 35 36 37 const int& a = mymay.at(); 38 008E6AA2 lea ecx,[mymay] 39 008E6AA5 call MyMat::at (08E154Bh) 40 #此時eax的值爲3,將3存入地址ebp-24h中, 41 008E6AAA mov dword ptr [ebp-24h],eax 42 #將eax的值變成ebp-24h 43 008E6AAD lea eax,[ebp-24h] 44 #將地址ebp-24h寫到地址爲a中,此時a表明的地址是ebp-24h 45 008E6AB0 mov dword ptr [a],eax 46 cout << a << endl;
因此結論就是:函數
一、返回值爲引用型(int& )的時候,返回的是地址,由於這裏用的是 int& a=mymay.at(); ,因此a和m_data_指的是同一塊地址(由寄存器eax傳回的5879712)。性能
二、返回值不是引用型(int)的時候,返回的是一個數值。這個時候就頗有意思了,編譯器是先將這個數值放入一個內存中(上面例子中,該內存地址爲ebp-24h),再把這個地址付給a,此時的a表明的地址是ebp-24h,和m_data_表明的地址不同(m_data_表明的地址是5879712)。優化
三、綜上兩點能夠看出,當返回的值不是引用型時,編譯器會專門給返回值分配出一塊內存的(例子中爲ebp-24h)。this
看下面的函數,返回的是t而不是&t,因此必定會有臨時變量產生。spa
1 T function1(){ 2 T t(0); 3 return t; 4 } 5 T x=function1();
這裏的過程是:
1.建立命名對象t
2.拷貝構造一個無名的臨時對象,並返回這個臨時對象
3.由臨時對象拷貝構造對象x
4.T x=function1();這句語句結束時,析構臨時對象
這裏一共生成了3個對象,一個命名對象t,一個臨時對象做爲返回值,一個命名對象x。code
下面的函數稍微複雜必定,它沒有先定義一箇中間變量t,看起來彷佛是直接返回了一個臨時變量。但實際上,若是不通過c++的優化,那麼它並無提升效率,由於它仍是建立了3個對象。htm
1 T function2(){ 2 return T(0); 3 } 4 T x=function2();
這裏的過程是:
1.建立一個無名對象
2.由無名對象拷貝構造一個無名的臨時對象
3.析構無名對象,返回臨時對象
4.由臨時對象拷貝構造對象x
5.T x=function2()語句結束時,析構臨時對象。
這裏一共生成了3個對象,其中有2個對象都是立刻被析構掉的,不能被後面的代碼使用。既然是這樣,那麼就會有優化的餘地,能夠嘗試着不要前面的兩個臨時變量。c++確實會作這樣的優化,優化後的c++會避免匿名對象和臨時對象這兩個對象的生成,而直接生成x,這樣就減小了兩次對象生成-回收的消耗,提升了程序性能。
其實function1()這段代碼也是會通過優化的,但由於臨時對象t是一個命名對象,因此必定會被建立。存儲返回值的臨時對象是多餘的,會被優化掉而不生成。可是,程序員不該該依賴這種優化,由於c++不保證這種優化必定會作。