从函数返回对象时是否有临时创建?

yes*_*aaj 1 c++ function

当一个函数有一个通过值传递的对象时,它使用复制构造函数或按位复制来创建临时放置在堆栈上以在函数内部使用,如何从函数返回一些对象?

//just a sample code to support the qn
rnObj somefunction()
{
return rnObj();
}
Run Code Online (Sandbox Code Playgroud)

并解释了如何将返回值带到被调用函数.

Hex*_*gon 6

可以通过其他答案来判断 - 编译器可以对此进行优化.

使用MSVC生成的具体示例,用于解释这是如何实现的(如其中一条评论中所述) -

上课 -

class AClass
{
public:
   AClass( int Data1, int Data2, int Data3 );

   int GetData1();

private:
   int Data1;
   int Data2;
   int Data3;
};
Run Code Online (Sandbox Code Playgroud)

随着以下琐碎的实施 -

AClass::AClass( int Data1, int Data2, int Data3 )
{
    this->Data1 = Data1;
    this->Data2 = Data2;
    this->Data3 = Data3;
}

int AClass::GetData1()
{
    return Data1;
}
Run Code Online (Sandbox Code Playgroud)

以下调用代码 -

AClass Func( int Data1, int Data2, int Data3 )
{
    return AClass( Data1, Data2, Data3 );
}

int main()
{
    AClass TheClass = Func( 10, 20, 30 );
    printf( "%d", TheClass.GetData1() );
}
Run Code Online (Sandbox Code Playgroud)

(printf()添加只是为了确保编译器不会优化所有内容......).
在非优化代码中,我们希望Func()在其堆栈上创建一个本地AClass,在那里构造它并将其复制为其返回变量.

但是,生成的程序集实际上看起来像(删除不需要的行) -

_TEXT SEGMENT
___$ReturnUdt$ = 8   ; size = 4
_Data1$ = 12         ; size = 4
_Data2$ = 16         ; size = 4
_Data3$ = 20         ; size = 4

mov     eax, DWORD PTR _Data3$[esp-4]
mov     ecx, DWORD PTR _Data2$[esp-4]
mov     edx, DWORD PTR _Data1$[esp-4]
push    esi
mov     esi, DWORD PTR ___$ReturnUdt$[esp]
push    eax
push    ecx
push    edx
mov     ecx, esi
call    ??0AClass@@QAE@HHH@Z    ; AClass::AClass
mov     eax, esi
pop     esi
ret     0
Run Code Online (Sandbox Code Playgroud)

3个函数变量从堆栈中提取并放入eax,ecx和edx中.
另外的第四个值被放入esi(并传递给ecx).
使用堆栈上的3个参数调用构造函数,并且ecx仍然包含第四个值.

我们来看看构造函数 -

_TEXT SEGMENT
_Data1$ = 8    ; size = 4
_Data2$ = 12   ; size = 4
_Data3$ = 16   ; size = 4

mov    edx, DWORD PTR _Data2$[esp-4]
mov    eax, ecx
mov    ecx, DWORD PTR _Data1$[esp-4]
mov    DWORD PTR [eax], ecx
mov    ecx, DWORD PTR _Data3$[esp-4]
mov    DWORD PTR [eax+4], edx
mov    DWORD PTR [eax+8], ecx

ret    12   ; 0000000cH
Run Code Online (Sandbox Code Playgroud)

3个构造函数参数被读入eax的偏移量 - eax是ecx的副本,是上面调用的第四个参数.
因此,构造函数构建了告诉它的对象--Func()的第四个参数.

而且,你猜对了,Func()的第四个参数实际上是整个程序中存在构造的AClass的真正单个位置.让我们看看main()的相关部分 -

_TEXT SEGMENT
_TheClass$ = -12    ; size = 12
_main PROC

sub    esp, 12

push   30
push   20
lea    eax, DWORD PTR _TheClass$[esp+20]
push   10
push   eax
call   ?Func@@YA?AVAClass@@HHH@Z    ; Func
Run Code Online (Sandbox Code Playgroud)

为AClass保留12个字节,并传递Func()的三个参数以及第四个参数 - 指向这12个字节.

这是特定编译器的特定示例.其他编译器的做法不同.但这就是事物的精神.