如果我想調用Bar()
而不是Foo()
,那麼Bar()
會返回給我一個Foo()返回的副本(額外開銷),或者返回Foo()
放置在臨時堆棧上的相同對象?函數返回另一個函數的返回
vector<int> Foo(){
vector<int> result;
result.push_back(1);
return result;
}
vector<int> Bar(){
return Foo();
}
如果我想調用Bar()
而不是Foo()
,那麼Bar()
會返回給我一個Foo()返回的副本(額外開銷),或者返回Foo()
放置在臨時堆棧上的相同對象?函數返回另一個函數的返回
vector<int> Foo(){
vector<int> result;
result.push_back(1);
return result;
}
vector<int> Bar(){
return Foo();
}
兩者都可能發生。但是,大多數編譯器在您優化後不會複製。
你的代碼表明應該有一個副本。但是,編譯器可以刪除任何不會更改語義和程序的副本。
注:這就是爲什麼你不應該有一個拷貝構造函數,做什麼,但複製正確,你永遠無法知道,如果一個副本將實際完成與否。
通常它會返回返回的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的結果。
我認爲這個解釋是有點矯枉過正... 而且高度依賴於編譯器。 – PierreBdR 2008-10-03 10:32:58
這是NRVO一個微不足道的情況下 - 的名字返回值優化(用詞不當在這種情況下,因爲沒有名字)。斯坦利普曼帽子blog entry與一個很好的解釋所涉及的機制。
不幸的是,這不是編譯器允許刪除副本的地方(內聯將盡管刪除它)。所以是的,一個矢量從Foo()複製到Bar(),然後從Bar()複製到調用者。已經做了很多工作來使std :: vector <>非常高效。所以別擔心。 – 2008-10-03 14:43:32
我認爲編譯器可以使用Return Value Optimization(http://msdn.microsoft.com/en-us/library/ms364057(VS.80).aspx)作爲單個副本安全地進行優化。 基本上,如果變量將被構造並立即複製,它可以直接構造它將被複制到的位置。 – 2008-10-03 15:31:41