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

C++20中拷贝与移动运算符的区别及删除它们的影响

关于C++移动运算符与EngineDevice类的疑问解答

一、先纠正你对移动操作的误解

移动不是“拷贝后删除原对象”,它的核心是转移对象持有的资源所有权,而非复制资源本身。

比如你的EngineDevice必然持有Vulkan设备句柄、内存缓冲区这类稀缺资源。移动操作会把这些资源的“控制权”从原对象转移给新对象,原对象会变成一个可安全销毁的空状态(不再持有任何有效资源,不会引发悬空指针问题),但原对象本身不会被立刻销毁——它的销毁仍由自身生命周期(比如离开作用域)决定。

举个简单例子:原对象A持有一个指向Vulkan设备的指针,移动构造新对象B后,B接管这个指针,A的指针被置为nullptr。后续A销毁时,因为指针为空,不会去释放已经属于B的资源。

二、允许移动运算符的影响

如果保留移动构造/赋值(不删除、自己实现或使用编译器默认生成的版本),会有这些效果:

  • 可以通过std::move()转移对象资源,比如:
    EngineDevice createDevice() { /* 创建并返回设备对象 */ }
    EngineDevice myDevice = createDevice(); // 语义上触发移动构造(编译器可能优化为直接构造)
    
  • 操作效率极高:不需要复制庞大的Vulkan资源,只是做几个指针的赋值操作。
  • 原对象移动后进入“有效但无资源”的状态——只能对它执行销毁或重新赋值操作,不能再用它操作原有的Vulkan资源。

三、删除移动运算符的影响

像教程里那样删除移动构造和赋值,会带来这些限制:

  • 完全禁止EngineDevice对象的资源转移:无法用std::move()转移对象,也不能让函数直接返回EngineDevice对象(因为返回值语义依赖移动)。
  • 强制对象的资源独占性:一个Vulkan资源只能被一个EngineDevice对象持有,且该对象的所有权不能被转移,只能在自身生命周期内使用,直到销毁。

四、为什么教程要删掉所有拷贝和移动?

在Vulkan图形引擎场景中,EngineDevice属于核心的独占资源类,这样设计的原因是:

  • 拷贝会导致多个对象持有同一Vulkan资源句柄,其中一个销毁时释放资源,剩余对象就会出现悬空指针,这一点你已经理解。
  • 移动虽然不会引发悬空指针,但部分引擎设计不希望设备对象的所有权被随意转移——比如设备是全局唯一实例,或绑定了固定的上下文资源,转移所有权可能打乱整个引擎的资源管理逻辑。
  • 删掉这些特殊成员函数,是从语法层面强制开发者遵守“设备对象独占资源、禁止复制/转移”的规则,避免误用。

补充:编译器默认的特殊成员函数

额外提一句:如果删除了拷贝构造和赋值,编译器不会自动生成移动构造和赋值;但教程特意删除移动操作,是明确表态“连移动也不允许”,彻底封死所有对象复制、转移的可能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 01:55:10