【问题标题】:why I got two temporary objects when returning a object from a function为什么从函数返回对象时我得到两个临时对象
【发布时间】:2013-07-28 09:22:52
【问题描述】:

这是我的 C++ 代码

class CTest {
public:
    int number;
    int arr[10];
};

CTest Return(int val) {
    CTest obj;
    obj.number = val;
    return obj;
}

int main() {
    CTest obj = Return(10);
    return 0;
}

查看汇编代码发现有两个临时对象

//in main

    CTest obj = Return(10);
0009F6CE  push        0Ah  
0009F6D0  lea         eax,[ebp-158h]  ; pass the first temporary object's address to Return
0009F6D6  push        eax  
0009F6D7  call        Return (0822E9h)  
0009F6DC  add         esp,8  
0009F6DF  mov         ecx,0Bh  
0009F6E4  mov         esi,eax  
0009F6E6  lea         edi,[ebp-124h]  ; copy from the first temporary object
0009F6EC  rep movs    dword ptr es:[edi],dword ptr [esi]  
0009F6EE  mov         ecx,0Bh  
0009F6F3  lea         esi,[ebp-124h]  
0009F6F9  lea         edi,[obj]       ; copy from the second temporary object
0009F6FC  rep movs    dword ptr es:[edi],dword ptr [esi]

//in Return

    CTest obj;
    obj.number = val;
0009F64E  mov         eax,dword ptr [val]  
0009F651  mov         dword ptr [obj],eax  
    return obj;
0009F654  mov         ecx,0Bh  
0009F659  lea         esi,[obj]  
0009F65C  mov         edi,dword ptr [ebp+8]  
0009F65F  rep movs    dword ptr es:[edi],dword ptr [esi]  ; copy to the first temporary object
0009F661  mov         eax,dword ptr [ebp+8]  

为什么我得到了第二个临时对象。似乎只有一个临时对象就足够了。如果我添加一个空析构函数~CTest() {} 将没有临时对象(RVO?)。

【问题讨论】:

  • 这是回报和分配(复制)。您的编译器显然没有执行复制省略。
  • 你编译的代码有没有优化?
  • 通过优化,我的编译器将 main 编译为:xor eax, eax; ret
  • 感谢 cmets。是的,我正在调试模式下学习汇编,没有优化。第一个临时是返回,第二个是分配,对吧?
  • 这是哪个编译器?是msvc吗?

标签: c++ assembly x86


【解决方案1】:

“为什么我得到了第二个临时对象”

可能是因为你关闭了优化。

否则,编译器将通过将 obj 从 main 作为隐藏参数(就像 this 指针)传递给 Return 函数来进行优化,并将“结果”分配给它。

所以优化后你的代码会是这样的:

void Return(void* put_result_here , int val) {
    CTest obj;
    obj.number = val;
    put_result_here = obj;
}


int main() {
    CTest obj; 
    Return(&obj , 10);
    return 0;
}

这种优化称为按值返回优化

【讨论】:

  • 转换不会用赋值代替构造。代码看起来更像:(void*) put_result_here{ obj = *(new (put_result_here) CTest); obj.number = val; },但在 main 中不会构造 obj。尝试为此做伪代码(恕我直言)非常具有误导性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-14
  • 2012-09-04
  • 1970-01-01
  • 1970-01-01
  • 2016-10-10
  • 1970-01-01
  • 2020-11-15
相关资源
最近更新 更多