删除拷贝构造函数后C++变量为何能通过函数返回值初始化?
删除拷贝/移动构造后返回值仍能初始化对象的原因分析
问题代码
class CameraBuffer; class CameraBufferAccessor{ friend CameraBuffer; private: CameraBufferAccessor(const int &data, const int &mutex); public: CameraBufferAccessor() = default; CameraBufferAccessor(const CameraBufferAccessor &) = delete; CameraBufferAccessor(CameraBufferAccessor &&) = delete; void operator=(const CameraBufferAccessor &other) = delete; void operator=(CameraBufferAccessor &&other) = delete; }; class CameraBuffer { public: const CameraBufferAccessor getReadAccess() const { return {1, 2}; } }; int main() { auto buffer = CameraBuffer(); CameraBufferAccessor a = buffer.getReadAccess(); CameraBufferAccessor b = a; }
问题解析
CameraBufferAccessor b = a;因拷贝构造被显式删除报错符合预期,但CameraBufferAccessor a = buffer.getReadAccess();能正常编译,核心原因是编译器触发了返回值优化(RVO),且这种优化不受拷贝/移动构造函数删除的限制:
- RVO的核心逻辑:当函数返回临时对象,且该对象直接用来初始化另一个同类型对象时,编译器会跳过中间的拷贝/移动步骤,直接在目标对象(
main中的a)的内存地址上构造返回值。不管你用return {1,2}还是return CameraBufferAccessor(1,2),只要符合条件,都会触发这个优化。 - 标准的特殊许可:C++标准明确规定,即使拷贝/移动构造函数被删除或不可访问,只要编译器可以执行RVO,代码依然合法。因为优化后的流程完全不需要调用拷贝/移动构造——对象直接在最终位置被构造。
- RVO触发的常见场景:
- 返回未命名临时对象(如
return CameraBufferAccessor(1,2)或列表初始化的临时对象) - 返回与返回类型完全匹配的局部变量(如函数内定义
CameraBufferAccessor temp(1,2); return temp;)
主流编译器(GCC、Clang、MSVC)默认开启RVO,若要禁用可使用编译选项-fno-elide-constructors,此时CameraBufferAccessor a = buffer.getReadAccess();会因无法调用拷贝/移动构造而报错。
- 返回未命名临时对象(如
内容的提问来源于stack exchange,提问作者SᴀQɪB M
相关产品推荐
相关产品推荐

