2008-10-03 17 views
7

Si quiero llamar Bar() en lugar de Foo(), hace Bar() me devolverá una copia (una sobrecarga adicional) de lo que vuelve foo(), o se devuelve el mismo objeto que Foo() lugares de la pila temporal ?Función devolver el regreso de otra función

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

Respuesta

10

Ambos pueden suceder. Sin embargo, la mayoría del compilador no copiará tan pronto como optimice.

Su código indican que debería ser una copia. Sin embargo, el compilador puede eliminar cualquier copia que no modifique la semántica y el programa.

Nota: Esto es por qué nunca debe tener un constructor de copia que hace nada, pero copiando correctamente como nunca se puede estar seguro de si una copia se hace realmente o no.

+0

Desafortunadamente, este no es un lugar desde el que el compilador puede eliminar la copia (sin embargo, eliminarlo). Entonces, sí, el vector se copia de Foo() a Bar() y luego se copia de Bar() a la persona que llama. Se ha trabajado mucho para que la copia std :: vector <> sea muy eficiente. Así que no te preocupes. –

+0

Creo que el compilador puede optimizar esto de forma segura como una copia única utilizando Return Value Optimization (http://msdn.microsoft.com/en-us/library/ms364057(VS.80).aspx). Básicamente, si la variable se construyera y se copiara de inmediato, puede simplemente construir directamente donde se copiaría. –

+0

Este es absolutamente un lugar donde se lleva a cabo la optimización, incluso sin tener en línea. – PierreBdR

2

Normalmente se devuelve una copia de la vector<int> devuelto. Sin embargo, esto depende en gran medida de la optimización realizada por el compilador. Vea la siguiente discusión.

generación de depuración

vector<int> Foo(){ 
004118D0 push  ebp 
004118D1 mov   ebp,esp 
004118D3 push  0FFFFFFFFh 
004118D5 push  offset [email protected]@YA?AV?$vecto[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] 
} 

Aquí podemos ver que para vector<int> result; se crea un nuevo objeto en la pila en [ebp-24h]

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

Cuando llegamos a return result; una nueva copia se crea en almacenamiento asignado por la persona que llama al [ebp+8]

00411943 mov   ecx,dword ptr [ebp+8] 
00411946 call  std::vector<int,std::allocator<int> >::vector<int,std::allocator<int> > (41104Bh) 

Y se llama al destructor para el parámetro local vector<int> result en [ebp-24h]

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

Release Build

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 

La línea de vector<int> result no llama al asignador de vectores, ya que se realiza en el sitio de llamadas Bar. La optimización no hace ninguna copia del resultado de Foo.

+0

Creo que esta explicación es un poco exagerado ... y altamente dependen del compilador. – PierreBdR

2

Este es un caso trivial para NRVO - nombres vuelven optimización de valor (un nombre poco apropiado en este caso, ya que no hay ningún nombre). Stan Lippman hat a blog entry con una buena explicación del mecanismo involucrado.

+1

¿No se llama simplemente RVO cuando el temporal no fue nombrado? –

+0

buen artículo, gracias. – jonner

+1

@David: Sí, por algunos, y solía llamarlo yo. Sin embargo, parece que no hay menciones de "RVO" en la literatura técnica. "NRVO" se utiliza como el término técnico que abarca esto. –

Cuestiones relacionadas