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

返回值优化(RVO)场景下析构函数被调用两次的原因探究

关于Copy Elision(拷贝省略)的析构函数调用疑问

你的示例代码:

#include "iostream"

using namespace std;

struct Foo
{
    Foo() { cout << "constructor was called" << endl; }
    ~Foo() { cout << "destructor was called" << endl; }
};

Foo f()
{
    Foo foo;
    return foo;
}

int main()
{
    Foo bla = f();
    return 0;
}

程序输出:

constructor was called
destructor was called
destructor was called

问题解析

你看到两次析构的核心原因是编译器没有启用「命名返回值优化(NRVO)」——比如你用了Debug模式编译,默认会关闭大部分优化。

具体执行流程是:

  1. 在f()函数内,foo对象正常构造(对应唯一一次构造输出)。
  2. 函数返回时,因为没有NRVO,编译器无法直接把foo的内存空间复用给main里的bla,所以会先析构foo(第一次析构输出),同时通过默认拷贝构造生成一个返回临时对象(你没自定义拷贝构造,所以这一步无输出)。
  3. 到main的Foo bla = f();语句时,编译器会执行「返回值优化(RVO)」,直接把这个临时对象构造在bla的内存空间里,因此临时对象不会额外触发析构。
  4. 最后main函数结束,bla超出作用域被析构(第二次析构输出)。

如果开启编译优化(比如GCC/Clang加-O2参数,MSVC加/O2),NRVO会生效:f()里的foo会直接构造在bla的内存空间中,此时只会输出一次构造和一次析构,完全符合你对拷贝省略的预期。

另外补充:C++17之后部分拷贝省略是强制行为,但NRVO至今仍是编译器可选的优化项,是否生效取决于编译模式和编译器实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 17:42:43