2008-10-03 158 views
7

如果我想調用Bar()而不是Foo(),那麼Bar()會返回給我一個Foo()返回的副本(額外開銷),或者返回Foo()放置在臨時堆棧上的相同對象?函數返回另一個函數的返回

vector<int> Foo(){ 
    vector<int> result; 
    result.push_back(1); 
    return result; 
} 
vector<int> Bar(){ 
    return Foo(); 
} 

回答

10

兩者都可能發生。但是,大多數編譯器在您優化後不會複製。

你的代碼表明應該有一個副本。但是,編譯器可以刪除任何不會更改語義和程序的副本。

注:這就是爲什麼你不應該有一個拷貝構造函數,做什麼,但複製正確,你永遠無法知道,如果一個副本將實際完成與否。

+0

不幸的是,這不是編譯器允許刪除副本的地方(內聯將盡管刪除它)。所以是的,一個矢量從Foo()複製到Bar(),然後從Bar()複製到調用者。已經做了很多工作來使std :: vector <>非常高效。所以別擔心。 – 2008-10-03 14:43:32

+0

我認爲編譯器可以使用Return Value Optimization(http://msdn.microsoft.com/en-us/library/ms364057(VS.80).aspx)作爲單個副本安全地進行優化。 基本上,如果變量將被構造並立即複製,它可以直接構造它將被複制到的位置。 – 2008-10-03 15:31:41

2

通常它會返回返回的vector<int>的副本。但是,這高度依賴於編譯器所做的優化。請參閱以下討論。

調試版本

vector<int> Foo(){ 
004118D0 push  ebp 
004118D1 mov   ebp,esp 
004118D3 push  0FFFFFFFFh 
004118D5 push  offset [email protected]@[email protected][email protected]@[email protected]@@[email protected]@XZ (419207h) 
004118DA mov   eax,dword ptr fs:[00000000h] 
004118E0 push  eax 
004118E1 sub   esp,0F4h 
004118E7 push  ebx 
004118E8 push  esi 
004118E9 push  edi 
004118EA lea   edi,[ebp-100h] 
004118F0 mov   ecx,3Dh 
004118F5 mov   eax,0CCCCCCCCh 
004118FA rep stos dword ptr es:[edi] 
004118FC mov   eax,dword ptr [___security_cookie (41E098h)] 
00411901 xor   eax,ebp 
00411903 push  eax 
00411904 lea   eax,[ebp-0Ch] 
00411907 mov   dword ptr fs:[00000000h],eax 
0041190D mov   dword ptr [ebp-0F0h],0 
    vector<int> result; 
00411917 lea   ecx,[ebp-24h] 
0041191A call  std::vector<int,std::allocator<int> >::vector<int,std::allocator<int> > (411050h) 
0041191F mov   dword ptr [ebp-4],1 
    result.push_back(1); 
00411926 mov   dword ptr [ebp-0FCh],1 
00411930 lea   eax,[ebp-0FCh] 
00411936 push  eax 
00411937 lea   ecx,[ebp-24h] 
0041193A call  std::vector<int,std::allocator<int> >::push_back (41144Ch) 
    return result; 
0041193F lea   eax,[ebp-24h] 
00411942 push  eax 
00411943 mov   ecx,dword ptr [ebp+8] 
00411946 call  std::vector<int,std::allocator<int> >::vector<int,std::allocator<int> > (41104Bh) 
0041194B mov   ecx,dword ptr [ebp-0F0h] 
00411951 or   ecx,1 
00411954 mov   dword ptr [ebp-0F0h],ecx 
0041195A mov   byte ptr [ebp-4],0 
0041195E lea   ecx,[ebp-24h] 
00411961 call  std::vector<int,std::allocator<int> >::~vector<int,std::allocator<int> > (411415h) 
00411966 mov   eax,dword ptr [ebp+8] 
} 

在這裏我們可以看到,對於vector<int> result;一個新的對象是在棧上的[ebp-24h]

00411917 lea   ecx,[ebp-24h] 
0041191A call  std::vector<int,std::allocator<int> >::vector<int,std::allocator<int> > (411050h) 

創建當我們到達return result;中創建一個新副本在[ebp+8]

00411943 mov   ecx,dword ptr [ebp+8] 
00411946 call  std::vector<int,std::allocator<int> >::vector<int,std::allocator<int> > (41104Bh) 
被調用者分配的存儲空間

和析構函數在[ebp-24h]

0041195E lea   ecx,[ebp-24h] 
00411961 call  std::vector<int,std::allocator<int> >::~vector<int,std::allocator<int> > (411415h) 

發佈呼籲本地參數vector<int> result構建

vector<int> Foo(){ 
00401110 push  0FFFFFFFFh 
00401112 push  offset [email protected]@[email protected][email protected]@[email protected]@@[email protected]@XZ (401F89h) 
00401117 mov   eax,dword ptr fs:[00000000h] 
0040111D push  eax 
0040111E sub   esp,14h 
00401121 push  esi 
00401122 mov   eax,dword ptr [___security_cookie (403018h)] 
00401127 xor   eax,esp 
00401129 push  eax 
0040112A lea   eax,[esp+1Ch] 
0040112E mov   dword ptr fs:[00000000h],eax 
00401134 mov   esi,dword ptr [esp+2Ch] 
00401138 xor   eax,eax 
0040113A mov   dword ptr [esp+8],eax 
    vector<int> result; 
0040113E mov   dword ptr [esi+4],eax 
00401141 mov   dword ptr [esi+8],eax 
00401144 mov   dword ptr [esi+0Ch],eax 
    result.push_back(1); 
    return result; 
00401147 push  eax 
00401148 mov   dword ptr [esp+28h],eax 
0040114C mov   ecx,1 
00401151 push  esi 
00401152 lea   eax,[esp+14h] 
00401156 mov   dword ptr [esp+10h],ecx 
0040115A mov   dword ptr [esp+14h],ecx 
0040115E push  eax 
0040115F lea   ecx,[esp+1Ch] 
00401163 push  ecx 
00401164 mov   eax,esi 
00401166 call  std::vector<int,std::allocator<int> >::insert (401200h) 
0040116B mov   eax,esi 
} 
0040116D mov   ecx,dword ptr [esp+1Ch] 
00401171 mov   dword ptr fs:[0],ecx 
00401178 pop   ecx 
00401179 pop   esi 
0040117A add   esp,20h 
0040117D ret 

vector<int> result不會調用矢量分配,因爲它是在調用點進行Bar。該優化不會複製Foo的結果。

+0

我認爲這個解釋是有點矯枉過正... 而且高度依賴於編譯器。 – PierreBdR 2008-10-03 10:32:58

2

這是NRVO一個微不足道的情況下 - 的名字返回值優化(用詞不當在這種情況下,因爲沒有名字)。斯坦利普曼帽子blog entry與一個很好的解釋所涉及的機制。