PIMPL惯用法中移动赋值操作编译失败原因排查问询
问题原因
C++标准规定:如果类显式声明了析构函数、拷贝构造函数、拷贝赋值运算符中的任意一个,编译器不会隐式生成默认的移动构造函数和移动赋值运算符。你的代码中为A声明了自定义析构函数,因此A类没有可用的移动赋值运算符。
对你的两个疑问的解答:
- 为什么编译器尝试调用拷贝赋值运算符?
std::move(b)返回的是A&&类型的右值,右值可以绑定到const A&类型的常量左值引用参数。由于找不到移动赋值运算符,编译器只能匹配到拷贝赋值运算符的重载,而这个运算符因为std::unique_ptr不支持拷贝,已经被默认删除,因此触发编译错误。 - 为什么移动逻辑没有生效?
std::unique_ptr本身支持移动赋值是事实,但外层A类没有对应的移动赋值运算符将移动操作转发给内部的m_x成员,移动链路没有打通,自然无法触发unique_ptr的移动逻辑。
解决方法
在struct.hpp的A类定义中,显式声明默认的移动特殊成员即可:
#pragma once #include <memory> struct A { std::unique_ptr<struct B> m_x; A(int x); ~A(); // 显式要求编译器生成默认移动构造和移动赋值 A(A&&) noexcept = default; A& operator=(A&&) noexcept = default; // 可选:显式删除拷贝成员,让报错信息更直观 A(const A&) = delete; A& operator=(const A&) = delete; };
注意:不要将上述移动成员的
=default实现放到struct.cpp中,否则main.cpp编译时无法找到移动赋值运算符的定义,会触发链接错误。
内容的提问来源于stack exchange,提问作者francesco
相关产品推荐
相关产品推荐

