2008-10-03 12 views
7

Foo() 대신 Bar()을 호출하려는 경우 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 <>를 매우 효율적으로 복사하기 위해 많은 작업이 수행되었습니다. 그러니 걱정하지 마십시오. –

+0

컴파일러가 반환 값 최적화 (http://msdn.microsoft.com/en-us/library/ms364057(VS.80).aspx)를 사용하여 이것을 안전하게 단일 복사본으로 최적화 할 수 있다고 생각합니다. 기본적으로 변수가 생성되어 즉시 복사되는 경우 복사 할 위치에 직접 구성 할 수 있습니다. –

+0

이것은 인라인 없이도 최적화가 이루어지는 절대적인 장소입니다. – PierreBdR

2

일반적으로 반송 된 사본 인 vector<int>을 반환합니다. 그러나 이것은 컴파일러가 수행하는 최적화에 크게 달려 있습니다. 다음 토론을 참조하십시오.

디버그 우리는 새로운 복사본이 생성됩니다 return result;에 도착하면 우리는 그 vector<int> result;에 대한 새로운 객체가 [ebp-24h]

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

에서 스택에 만들어 볼 수 있습니다 여기에

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] 
} 

구축 호출자가 할당 한 저장소 [ebp+8]

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

그리고 그것에서 호출 사이트에서 수행되기 때문에 소멸자는 벡터 할당을 호출하지 않습니다

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 구축 [ebp-24h]

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

릴리스에서 로컬 매개 변수 vector<int> result에 대해 호출됩니다 Bar. 최적화는 Foo의 결과를 복사하지 않습니다.

+0

나는이 설명이 약간 과잉이라고 생각한다 ... 그리고 고도로 컴파일러에 의존한다. – PierreBdR

2

이것은 NRVO - 이름 반환 값 최적화 (이 경우 이름이 없으므로 잘못된 이름)에 대한 간단한 사례입니다. Stan Lippman은 blog entry에 관련된 메커니즘에 대해 설명합니다.

+1

임시 이름이 지정되지 않은 경우 RVO가 아닌가요? –

+0

멋진 기사, 감사합니다. – jonner

+1

@David : 예, 일부는 그렇습니다. 그러나 기술 문헌에 "RVO"에 대한 언급이없는 것 같습니다. "NRVO"는이를 포괄하는 전문 용어로 사용됩니다. –