C++11起禁用拷贝构造函数应使用MyClass(const MyClass&) = delete;,需在类内声明且必须同步禁用拷贝赋值operator=,否则逻辑不一致;未声明则编译器可能自动生成,默认行为易导致误用或隐蔽错误。

如何用 delete 禁用拷贝构造函数
直接在类内声明拷贝构造函数并用 = delete 修饰,编译器就会拒绝所有隐式或显式的拷贝操作。这是 C++11 起最标准、最彻底的禁用方式。
-
MyClass(const MyClass&) = delete;必须写在类定义内部(通常放在private或public区均可,但建议public下明确表达设计意图) - 不需要实现体,也不允许实现;一旦声明为
delete,连友元函数都无法调用它 - 如果只禁用拷贝构造但没禁用拷贝赋值,编译器仍会自动生成默认的
operator=—— 这往往导致逻辑不一致,应一并禁用
为什么不能只删掉拷贝构造函数声明
不写拷贝构造函数,不代表它被禁用;编译器会自动生成一个默认的公有拷贝构造函数,只要成员都可拷贝,这个函数就有效。这和“想禁止却忘了禁”是两回事。
- 未声明 + 所有成员可拷贝 → 编译器合成公有拷贝构造函数
- 未声明 + 某个成员不可拷贝(如含
std::mutex)→ 编译失败,但错误位置在使用点而非定义点,排查困难 -
= delete是主动声明“我明确不要”,错误发生在调用处,信息清晰,且能阻止任何误用
禁用拷贝时必须同步处理的函数
禁用拷贝构造函数后,若类还支持移动语义,必须显式定义或删除移动操作,否则可能引发意外行为。
- 拷贝构造和拷贝赋值要成对
= delete:MyClass& operator=(const MyClass&) = delete; - 若类含资源(如指针、文件句柄),又不想支持移动,也应禁用移动构造和移动赋值:
MyClass(MyClass&&) = delete;和MyClass& operator=(MyClass&&) = delete; - 如果不删移动函数,而类又有不可拷贝成员(如
std::unique_ptr),编译器可能因“移动可行”而静默禁用拷贝,但这种依赖推导的行为容易误判,不如显式控制
常见误用:在模板类中错误地使用 delete
模板类里禁用拷贝需注意实例化时机 —— = delete 声明本身会被实例化,但错误只在真正调用时触发。这对 SFINAE 或概念约束场景尤其关键。
立即学习“C++免费学习笔记(深入)”;
- 错误写法:
template—— 合法,但对所有struct Holder { Holder(const Holder&) = delete; }; T都禁用 - 若只想对某些
T禁用(如当T不可拷贝时),不能靠delete条件化,得用static_assert或概念约束 - 更隐蔽的问题:基类模板中
= delete的拷贝构造,在派生类未显式声明拷贝函数时,可能导致派生类对象无法被拷贝,且错误提示指向派生类而非基类
= delete 就完事;它牵扯到移动语义是否开放、资源管理策略是否统一、以及模板实例化时的边界行为。最容易被忽略的是拷贝赋值函数——很多人只删了构造函数,结果对象能赋值却不能初始化,逻辑割裂比完全不禁用还难调试。










