7 votes

Fonction renvoyant le retour d'une autre fonction

Si je veux appeler Bar() au lieu de Foo() , fait Bar() me renvoie une copie (surcharge supplémentaire) de ce que Foo() renvoie, ou il renvoie le même objet qui Foo() sur la pile temporaire ?

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

10voto

PierreBdR Points 11479

Les deux peuvent se produire. Cependant, la plupart des compilateurs n'effectuent pas de copie dès que vous optimisez.

Votre code indique qu'il devrait y avoir une copie. Cependant, le compilateur est autorisé à supprimer toute copie qui ne change pas la sémantique et le programme.

Note : C'est la raison pour laquelle vous ne devriez JAMAIS avoir un constructeur de copie qui ne fait rien d'autre que copier correctement car vous ne pouvez jamais être sûr qu'une copie sera réellement effectuée ou non.

2voto

smink Points 39640

Normalement, il renvoie une copie de l'objet retourné vector<int> . Cependant, cela dépend fortement de l'optimisation effectuée par le compilateur. Voir la discussion suivante.

Debug Build

vector<int> Foo(){  
004118D0  push        ebp  
004118D1  mov         ebp,esp 
004118D3  push        0FFFFFFFFh 
004118D5  push        offset __ehhandler$?Foo@@YA?AV?$vector@HV?$allocator@H@std@@@std@@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] 
}  

Ici, nous pouvons voir que pour vector<int> result; un nouvel objet est créé sur la pile à [ebp-24h]

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

Quand on arrive à return result; une nouvelle copie est créée dans le stockage alloué par l'appelant à [ebp+8]

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

Et le destructeur est appelé pour le paramètre 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 __ehhandler$?Foo@@YA?AV?$vector@HV?$allocator@H@std@@@std@@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 ligne vector<int> result n'appelle pas l'allocateur de vecteur car cela est fait au niveau du site d'appel en Bar . L'optimisation ne fait aucune copie du résultat de Foo.

2voto

Konrad Rudolph Points 231505

Il s'agit d'un cas trivial d'optimisation de la valeur de retour des noms (un terme mal choisi dans ce cas puisqu'il n'y a pas de nom). Stan Lippman a fait un entrée de blog avec une belle explication du mécanisme impliqué.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X