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

为何简单场景下返回不可拷贝不可移动右值时拷贝消除不生效?

为何简单场景下拷贝消除对具名右值无效?C++标准是否存在技术障碍?

我搞不懂为什么在简单场景下,拷贝消除(copy elision)对具名右值不起作用?C++标准里加入这个特性有技术障碍吗?这个问题曾在《How does guaranteed copy elision work?》线程中被部分讨论,但没得到完整解答。

符合预期运行的示例

struct x {
   x(int) {}

   void bar() {}

   x(x&&) = delete;
   x& operator=(x&&) = delete;
};

x foo1()
{
  return x{1};  // 正常编译运行
}

我理解调用foo1时,编译器会通过类似this的隐式参数传递变量构造的存储地址,这也是拷贝消除生效时返回值无额外开销的原因。

无法生效的场景

但如果是在函数中间构造对象再返回,这个机制就失效了:

x foo2()
{
  auto r = x{1};
  r.bar();
  return r;     // 编译报错
}

编译时的错误信息:

g++ -c --std=c++2a 1.cpp 
1.cpp: In function ‘x foo2()’:
1.cpp:19:10: error: use of deleted function ‘x::x(x&&)’
   19 |   return r;
      |          ^
1.cpp:6:9: note: declared here
    6 |         x(x&&) = delete;
      |         ^

在我看来,这种单个变量的场景下,编译器完全可以像foo1那样,在指定存储位置构造x对象并返回。而且如果启用x的移动构造函数,调用foo2时编译器并不会调用它——这就是具名返回值优化(NRVO),但为什么删除移动构造后就不行了?

明确理解的无效场景

以下场景无法生效的原因我完全清楚:

x foo3()
{
  auto r1 = x{1};
  auto r2 = x{2};

  return condition ? r1 : r2;
}

这段代码创建了两个对象,返回其中一个必须使用move操作,这个逻辑没问题。但单个变量的情况我始终无法理解。

可行的临时解决方案

顺带一提,有个在部分场景下可行的 workaround:

struct y: x
{
   y(int i)
      : x(i)
   {
      bar();
   }
};

y foo3()
{
  return y{1}; // 不直接返回x,而是返回派生类y,所有操作都在y的构造函数中完成
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 21:13:00