Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What comes first - stack unwinding or copying of return values

Tags:

c++

Is the mutex used in method GetValues() released before or after copy constructing the dummy instance?

class Protect
{};

class Test
{
public:
    Protect GetValues() const;

private:
    Protect m_protVal;
    Mutex m_mutex;
};

Protect Test::GetValues() const
{
    CLockGuard lock(m_mutex);

    return m_protVal;
}

int main(int argc, char** argv)
{
    Test myTestInstance;

    Protect dummy = myTestInstance.GetValues();
}

Let's assume CLockGuard and Mutex are standard classes provided with boost lib.

like image 221
nabulke Avatar asked Jan 19 '12 08:01

nabulke


2 Answers

Yes:-). Formally, there are two “copies” when returning a value: one to some special place used to actually return the value, and the second after the return, to wherever the value must be finally placed. Either or both can be optimized out, however. The destruction of local variables occurs after the first, but before the second. (NRVO and RVO may lead to the first being optimized out, but they don't affect your code, since you're not returning a local variable.)

like image 100
James Kanze Avatar answered Oct 06 '22 00:10

James Kanze


As of Visual C++, using MSVC 9.0, the following code

int add(int x, int y)
{
    int z;
    z = x + y;
    return z;
}

int _tmain(int argc, _TCHAR* argv[])
{
    add(10, 20);
    return 0;
}

results in assembly

int add(int x, int y)
{
013613A0  push        ebp  //save the frame pointer
013613A1  mov         ebp,esp 
013613A3  sub         esp,0CCh 
013613A9  push        ebx  
013613AA  push        esi  
013613AB  push        edi  
013613AC  lea         edi,[ebp-0CCh] 
013613B2  mov         ecx,33h 
013613B7  mov         eax,0CCCCCCCCh 
013613BC  rep stos    dword ptr es:[edi] 
    int z;
    z = x + y;
013613BE  mov         eax,dword ptr [x] //load x
013613C1  add         eax,dword ptr [y] //add y to x
013613C4  mov         dword ptr [z],eax //store the result to z
    return z;
013613C7  mov         eax,dword ptr [z] //store the return value in eax
}
013613CA  pop         edi  //unwind the stack
013613CB  pop         esi  
013613CC  pop         ebx  
013613CD  mov         esp,ebp 
013613CF  pop         ebp  
013613D0  ret

int _tmain(int argc, _TCHAR* argv[])
{    
013613E0  push        ebp  
013613E1  mov         ebp,esp 
013613E3  sub         esp,0C0h 
013613E9  push        ebx  
013613EA  push        esi  
013613EB  push        edi  
013613EC  lea         edi,[ebp-0C0h] 
013613F2  mov         ecx,30h 
013613F7  mov         eax,0CCCCCCCCh 
013613FC  rep stos    dword ptr es:[edi] 
    add(10, 20);
013613FE  push        14h  
01361400  push        0Ah  
01361402  call        add (136109Bh) 
01361407  add         esp,8 
    return 0;
0136140A  xor         eax,eax //store 0 to eax, the return value holder
}
0136140C  pop         edi  //unwind the stack
0136140D  pop         esi  
0136140E  pop         ebx  

This makes me say that return value is stored first and then the stack unwinding happens!

like image 31
Chethan Ravindranath Avatar answered Oct 05 '22 22:10

Chethan Ravindranath