You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++按值返回对象时地址不同?Copy Elision为何未生效?

关于拷贝消除(Copy Elision)的地址差异问题

核心原因分析

1. 命名返回值优化(NRVO)的可选性

你的代码中test()函数返回的是命名局部对象obj1,这属于NRVO的场景。虽然C++17强制了针对临时对象的返回值优化(RVO),但NRVO仍然是编译器的可选优化,而非强制要求:

  • 在g默认的-O0(调试模式)下,编译器为保留调试信息、方便断点调试,通常会禁用NRVO。此时obj1会在test()的栈帧中构造,返回时编译器会利用C17的保证拷贝消除规则,直接将obj1的内容“转移”到main()的obj2位置,但不会复用同一个栈空间,因此两者地址不同。
  • 你添加拷贝、移动构造函数后没有输出,是因为编译器确实消除了拷贝/移动操作(符合C++17的保证拷贝消除),但因未启用NRVO,对象存储位置分属两个栈帧,所以地址仍不同。

2. vector地址一致的误解

你提到返回vector时地址一致,大概率是指vector内部堆内存的地址,而非vector对象本身的地址:

  • vector的底层数据存储在堆上,返回vector时,即使编译器未启用NRVO,移动构造函数也会直接将内部指针转移给目标对象,不会拷贝堆数据,因此内部数据的地址会一致。若打印vector对象本身的地址,在-O0模式下同样会和函数内的vector对象地址不同。

验证方法

若想看到NRVO生效后的地址一致效果,可开启优化编译:

g++ -std=c++20 -O2 your_code.cpp

此时编译器会启用NRVO,直接在main()的obj2位置构造test()中的obj1,两者地址完全相同,同时拷贝/移动构造函数也不会被调用。

补充说明

  • 即使未启用NRVO,C++17的保证拷贝消除也会避免拷贝/移动操作的实际执行,这就是你添加构造函数后没有输出的原因。
  • 调试模式下的地址差异是编译器为调试便利性做出的选择,并不代表拷贝消除未发生。

内容的提问来源于stack exchange,提问作者Shivanshu Arora

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 05:40:35