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

C++移动构造函数被删除与未自动生成的差异问题

问题解答

第一个示例可正常编译的核心原因

你对移动构造隐式生成规则的记忆存在一处关键遗漏:当类满足「编译器不隐式生成移动构造/移动赋值运算符」的条件时,针对右值的构造/赋值请求不会直接报错,而是会在重载决议阶段回退匹配拷贝操作。

首先看第一个结构体定义:

struct A
{
    A() = default;
    A(const A&) = default;
};

这个结构体确实不会被编译器隐式生成移动构造函数,但有两个关键点容易被忽略:

  • std::move本身不执行任何移动操作,它唯一的作用是把传入参数强制转换为右值引用类型,最终调用哪个函数完全由重载决议决定。
  • const左值引用可以绑定右值,因此const A&类型的参数是可以接收A&&类型实参的。

因此A a2 = std::move(a1);这行代码执行时,重载决议找不到可用的A(A&&)移动构造,就会自动匹配到你显式声明的A(const A&)拷贝构造,最终实际调用的是拷贝逻辑而非移动逻辑,自然可以正常编译通过。

显式delete移动构造与不生成移动构造的本质区别

两种状态的核心差异是移动构造函数是否进入重载决议的候选集合:

  • 编译器不隐式生成移动构造时:A(A&&)这个函数签名根本不存在于候选列表中,重载决议会直接跳过它,寻找参数可匹配的次优重载,也就是能接收右值的const拷贝构造,匹配成功就正常执行。
  • 显式声明A(A&&) = delete时:这个函数是真实存在于重载候选集的,且对于A&&类型的入参,A(A&&)的匹配优先级高于A(const A&),重载决议会直接选中这个被标记为删除的函数,因此触发编译错误,和你观察到的现象完全一致。

你给出的第二个结构体定义就属于这种场景:

struct A
{
    A() = default;
    A(const A&) = default;
    A(A&&) = delete;
};

这时候A a2 = std::move(a1);会优先匹配被删除的移动构造,因此编译失败。

补充规则说明

C标准中对移动操作的隐式生成有明确约束:只要类显式声明了拷贝构造、拷贝赋值运算符、析构函数三者中的任意一个,编译器就不会隐式生成移动构造和移动赋值运算符。这一设计是为了兼容C11标准之前的旧代码:旧代码不存在移动语义,所有右值的拷贝、传值场景本来就是靠const引用参数的拷贝构造处理的,不会因为新标准推出就导致海量旧代码无法编译。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 04:45:38