直接返回结构体还是填充指针?拷贝消除下的性能等价性探讨
拷贝消除是否能让返回结构体的初始化函数性能与指针版本相当?
这是个很棒的问题!答案是是的——在启用优化的情况下,借助返回值优化(Return Value Optimization,RVO,拷贝消除的一种核心实现),第二种返回结构体的实现会被编译器优化到和指针版本性能几乎完全一致的程度。
为什么你在Godbolt里看不到有效对比?
你遇到的代码被完全优化掉的情况,是因为编译器发现你的初始化函数调用后,没有任何实际依赖结构体数据的操作(比如没有读取x/y的值,也没有把结构体传递给其他需要它的函数)。这种情况下,编译器会直接把整个函数调用逻辑删掉——毕竟它对程序的最终输出没有任何影响。
如何测试才能看到真实的汇编对比?
要让编译器保留初始化相关的代码,你需要给它一个“必须保留逻辑”的理由:比如调用函数后,使用结构体的成员(打印、赋值给全局变量,或者传递给另一个无法被优化的函数)。举个可测试的示例代码:
#include <stdio.h> struct data { int x; int y; }; // 指针版本初始化函数 void init_data_ptr(struct data *d) { d->x = 5; d->y = 10; } // 返回结构体版本初始化函数 struct data init_data_ret(void) { struct data d = {5, 10}; return d; } int main() { struct data d1, d2; init_data_ptr(&d1); d2 = init_data_ret(); // 强制使用结构体成员,避免编译器优化掉初始化逻辑 printf("%d %d\n", d1.x, d1.y); printf("%d %d\n", d2.x, d2.y); return 0; }
优化后的实际效果
当你用-O2或-O3这类优化标志编译这段代码时,查看汇编会发现:init_data_ret的执行逻辑和init_data_ptr几乎完全一致——编译器会直接在调用者(main函数)的栈空间里构造返回的结构体,不会产生任何额外的拷贝操作。这就是RVO的核心作用:它消除了从函数返回结构体时原本需要的拷贝步骤,让返回结构体的写法和指针写法在性能上没有差异。
额外说明
返回值优化是现代编译器(GCC、Clang、MSVC等)默认开启的优化特性,只要你的代码符合RVO的基础条件(比如返回的是单一局部变量,没有复杂分支返回不同变量等),就可以放心使用返回结构体的写法,不用担心性能损失。
内容的提问来源于stack exchange,提问作者Michael Smith
相关产品推荐
相关产品推荐

