C++函数返回值作为值传递实参时,仅产生1个还是2个临时变量?
问题解答
你提到的传函数返回值作为按值传参的实参场景,不会生成两个临时变量,结论和你测试的结果一致:
具体规则说明
- C++17及更高版本:标准强制要求复制消除,当
make_foo(args)这类纯右值(无标识、只能取右值引用的表达式)用来初始化同类型的对象时,不需要生成中间临时量,直接在目标对象的内存地址上构造。也就是说make_foo的返回值会直接构造在func的形参foo的地址上,全程只会生成1个对象。 - C++11/14版本:虽然复制消除不是强制要求,但GCC、Clang、MSVC等主流编译器在默认优化等级下都会执行返回值优化(RVO),同样会省略中间临时量的构造,仅生成1个对象。就算关闭优化,绝大多数编译器也会对这种简单场景做优化。
你的测试结果解释
你的测试代码里test(std::shared_ptr<int>(sp))调用中,std::shared_ptr<int>(sp)是纯右值,用来初始化test的形参:
- 初始状态下main函数里的
sp和sp2持有两个引用,所以计数为2 - 编译器直接把新构造的
shared_ptr生成在形参的内存地址上,只新增1个引用,所以计数输出为3,不存在额外的中间临时对象,自然不会出现计数到4的情况 - test函数执行完成后形参销毁,引用计数回到2,和你拿到的运行结果完全匹配
你疑惑的“第一个变量是否被释放”其实不存在,因为整个过程中根本没有生成那个额外的中间临时变量,自然也不存在它的作用域结束被释放的逻辑。
唯一会生成两次对象的场景
只有你手动把返回值绑定到一个左值变量,再传参的时候才会触发两次构造:
void func(Foo foo){..} // 这种写法会生成两个Foo对象 Foo tmp = make_foo(args); func(tmp);
这种场景下首先会构造tmp对象,按值传参给func的时候会再拷贝构造一次形参,才会出现两个对象。
内容的提问来源于stack exchange,提问作者nowisbest
相关产品推荐
相关产品推荐

