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

C++中A d(b+c)未触发移动构造函数?求原因与标准依据

问题解析:A d(b+c)为何未调用移动构造函数?

示例代码

#include <iostream>
using namespace std;

class A{
  char a;
public:
  A(): a('#') { cerr << "DEFAULT!" << endl; };
  A(char a): a(a) { cerr << "VALUE! " << a << endl;  };
  A(A const &o): a(o.a) { cerr << "COPY! " << o.a << endl; }
  // A(A && o): a(std::move(o.a)) { cerr << "MOVE!: " << o.a << endl; }
  // A(const A && o): a(std::move(o.a)) { cerr << "MOVE!(const): " << o.a << endl; }
  // A(volatile A && o): a(std::move(o.a)) { cerr << "MOVE!(volatile): " << o.a << endl; }
  // A(const volatile A && o): a(std::move(o.a)) { cerr << "MOVE!(const volatile): " << o.a << endl; }
  // A(A && o) = delete; // (***)
  friend A operator+(const A &o1, const A &o2){ A r; r.a = o1.a -'a' + o2.a; cerr << "+:" << r << endl; return r; }
  friend ostream& operator<<(ostream& out, const A& o) { out << o.a; return out; }
};

int main(){
  A a('a');
  A b('b');
  A c('c');
  cout << a << b << c << endl;
  A d(b+c); // <----- !!! WHO HANDLES THIS??? !!!
  A e(a);
  cout << a << b << c << d << e << endl;
  return 0;
}

问题描述

在A d(b+c)这一行,预期会调用默认移动构造函数,但手动重载的移动构造函数并未被触发;删除默认拷贝构造函数后,gcc/clang编译器报错提示默认移动构造函数已被删除。使用编译器版本为clang 10.0.0-4ubuntu1、g++ 9.4.0-1ubuntu1~20.04.2。

原因解释

1. 拷贝省略(Copy Elision)优化

编译器会执行返回值优化(RVO)/命名返回值优化(NRVO),直接在目标对象d的内存空间中构造operator+返回的临时对象,完全跳过拷贝或移动构造函数的调用流程。这就是为什么你看不到移动构造函数的输出——因为它根本没被执行。

可以通过添加编译选项-fno-elide-constructors关闭拷贝省略,此时如果存在合法的移动构造函数,就能看到它被调用的日志。

2. 默认移动构造函数的生成规则

根据C标准(C11及后续版本):如果类中存在用户显式声明的拷贝构造函数、拷贝赋值运算符或析构函数,编译器会自动抑制默认移动构造函数和移动赋值运算符的生成。

你的代码中显式定义了拷贝构造函数A(A const &o),因此类A没有默认生成的移动构造函数。当你删除拷贝构造函数后,A d(b+c)需要用移动构造来接收右值,但此时移动构造函数既没有用户定义,也没有默认生成,所以编译器报错。

标准参考

C标准规定:当类有用户声明的拷贝构造、拷贝赋值或析构函数时,隐式移动构造函数会被定义为删除的(或者说不被生成)。这是为了兼容C03的代码行为,避免意外的移动语义破坏原有逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 18:32:41