当一个函数的按值返回直接按值传递给另一个函数时,我正在检查普通和非普通可复制类型之间的复制省略。对于非平凡的情况,似乎对象是按预期直接传输的,但对于平凡的情况,似乎输出对象被复制到堆栈上以生成第二个函数的输入对象。我的问题是,为什么?
如果这是意料之中的,那就令人惊讶了,因为非平凡可复制类型在这些函数之间传递的效率更高。
资源:
struct Trivial_Struct
{
unsigned char bytes[ 4 * sizeof( void* ) ];
};
struct Nontrivial_Struct
{
unsigned char bytes[ 4 * sizeof( void* ) ];
Nontrivial_Struct( Nontrivial_Struct const& );
};
Trivial_Struct trivial_struct_source();
Nontrivial_Struct nontrivial_struct_source();
void trivial_struct_sink( Trivial_Struct );
void nontrivial_struct_sink( Nontrivial_Struct );
void test_trivial_struct()
{
trivial_struct_sink( trivial_struct_source() );
}
void test_nontrivial_struct()
{
nontrivial_struct_sink( nontrivial_struct_source() );
}
GCC 输出汇编:
test_trivial_struct():
sub rsp, 40
mov rdi, rsp
call trivial_struct_source()
push QWORD PTR [rsp+24]
push QWORD PTR [rsp+24]
push QWORD PTR [rsp+24]
push QWORD PTR [rsp+24]
call trivial_struct_sink(Trivial_Struct)
add rsp, 72
ret
test_nontrivial_struct():
sub rsp, 40
mov rdi, rsp
call nontrivial_struct_source()
mov rdi, rsp
call nontrivial_struct_sink(Nontrivial_Struct)
add rsp, 40
ret
神螺栓.org。我尝试了 GCC、Clang 和 MSVC;GCC 的程序集对我来说更容易阅读,但所有编译器似乎都为简单可复制的情况编写了类似的代码。
杂项:
- 显然,如果我将类定义中的
Nontrivial_Struct( Nontrivial_Struct const& ) = default
复制构造函数声明为;如果我在类定义之后添加Nontrivial_Struct::Nontrivial_Struct( Nontrivial_Struct const& ) = default;
,那么它仍然很重要。 - 我可以将“4”更改为较大的值,例如“64”,它仍然会发生。
推测:
- 这是与 C ABI 的向后兼容性吗?
- 它与http://eel.is/c++draft/class.temporary#3有什么关系吗?