用=delete禁用构造函数需在public区声明,成对禁用拷贝构造与赋值,模板中宜用static_assert替代直接删除,禁用拷贝不影响移动语义。

如何用 = delete 禁用特定构造函数
直接在目标构造函数声明后加 = delete 即可,编译器会在任何调用点立即报错,不生成该函数的任何实现。
常见错误现象:只禁用拷贝构造却漏掉拷贝赋值;或把 = delete 写在 private 区域——它必须是 public(否则友元或成员仍可能意外调用,且 IDE 提示不全)。
-
= delete不限制访问权限,只彻底移除函数符号;放在public才能确保所有调用(包括类内、继承、模板实例化)都被拦截 - 禁用单参构造时,尤其要注意隐式转换场景:比如
MyClass(int)允许MyClass x = 42;,若不想这样,就写MyClass(int) = delete; - 若类有多个构造函数,只对某一个
= delete,其余照常可用;但注意:一旦你定义了任意构造函数,编译器就不会再自动生成默认构造,如需保留,得显式写MyClass() = default;
禁用拷贝构造 + 拷贝赋值必须成对出现
只删 MyClass(const MyClass&) 而不删 operator=,对象仍可通过赋值语句被“复制”;反之亦然。二者缺一不可,否则设计意图失效。
- 正确写法(都在
public下):MyClass(const MyClass&) = delete;MyClass& operator=(const MyClass&) = delete; - 错误写法示例:
仅删构造函数 →MyClass a; MyClass b = a;报错,但a = MyClass{};仍能通过
仅删赋值运算符 →MyClass a, b; b = a;报错,但MyClass c = a;仍能通过 - 继承时子类不会自动继承
= delete,若子类未显式定义拷贝函数,它默认不生成;但若子类写了自己的拷贝构造,就得手动再次= delete
在模板类中安全禁用拷贝的坑
模板类里直接写 T(const T&) = delete; 极易触发 SFINAE 失败或编译器抱怨 “deleted function is not trivially copyable”,本质是模板参数约束没兜住。
- 更稳妥的做法是用
static_assert检查类型是否满足条件,再决定是否允许拷贝:templateclass Wrapper { static_assert(!std::is_copy_constructible_v , "T must not be copyable"); ... }; - 或者用
std::enable_if控制特化版本的生成,而非粗暴= delete - 别在模板定义体内对
this类型直接= delete拷贝函数——这会让编译器在实例化时无法推导,报错位置远离实际使用点,调试困难
delete 后 move 是否还能用
完全不受影响。禁用拷贝不等于禁用移动;只要没显式删除移动函数,且类满足移动语义前提(如无用户定义的拷贝/析构/移动),std::move 和容器 emplace_back 依然有效。
- 想同时禁用移动,必须额外声明:
MyClass(MyClass&&) = delete;MyClass& operator=(MyClass&&) = delete; - 禁用拷贝后,
std::vector仍可工作——前提是插入时用emplace_back或确保元素可移动;若强行push_back(MyClass{}),会因拷贝失败而报错 - 某些资源持有类(如文件句柄代理、单例包装器)确实需要全禁,但多数场景下保留移动是合理选择,避免深拷贝开销
最易忽略的是:delete 的函数在类内成员函数中也调用失败,不是“外部不可见”而是“根本不存在”。这点和旧式 private 声明有本质区别,也是它真正安全的核心所在。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











