=default 用于让编译器生成高效标准的默认函数实现,=delete 用于编译期精准禁用函数;前者在用户定义构造函数后成为刚需,后者可防止浅拷贝等运行时错误并拦截隐式转换。

直接说结论:=default 是让编译器生成高效、标准的默认实现;=delete 是在编译期彻底封禁某个函数调用,比 C++03 的 private + 不实现更早报错、更准、更安全。
什么时候必须用 =default 才能编译通过
只要你写了任何用户定义的构造函数(哪怕只有一个带参构造),编译器就不再自动生成默认构造函数——这时 =default 就不是“可选”,而是刚需。
- 比如
class Widget { public: Widget(int x) {} };,Widget w;会编译失败;加一行Widget() =default;就恢复可用 - 析构函数也一样:基类若需支持多态删除(
delete base_ptr),又不想手写空虚析构体,就写virtual ~Base() =default;——编译器生成的虚析构函数效率更高,且天然满足 ABI 兼容 - 移动操作符常被隐式抑制:一旦你声明了拷贝构造或拷贝赋值,编译器就不会自动生成移动函数;想启用移动语义,就得显式写
Widget(Widget&&) =default;
=delete 禁用拷贝是最常见也最容易漏的点
很多 RAII 类(如文件句柄、锁、唯一资源管理器)本就不该被拷贝,但不显式 =delete,编译器就会悄悄生成拷贝函数,导致浅拷贝、双重释放、状态撕裂等运行时灾难。
- 正确写法是成对删除:
MyClass(const MyClass&) =delete;和MyClass& operator=(const MyClass&) =delete; - 别用
private+ 不实现的老办法:链接时报错太晚,IDE 不提示,模板实例化时甚至可能静默跳过 - 注意位置:必须在类内首次声明时就
=delete,不能先声明再在类外定义时删
函数签名不匹配时 =delete 能精准拦截隐式转换
=delete 不只用于特殊成员函数,还能作用于普通成员函数或自由函数,用来堵住你不想要的类型转换路径。
立即学习“C++免费学习笔记(深入)”;
- 比如日志类想接受
int但拒绝double:void log(double) =delete;,那么log(3.14)编译失败,而log(42)正常 - 防止
char意外转成整数构造:MyInt(char) =delete;,MyInt('a')直接报错,避免魔数误用 - 模板中也能删:
template<typename t> void process(T) =delete;</typename>再特化需要的版本,实现“白名单”接口
容易忽略的细节和陷阱
=default 函数不能有默认参数;=delete 的函数不能是 const 限定或 noexcept 修饰后再删(语法错误);二者都只能用于函数声明,不能用于定义体。
-
=default在类外定义时,必须和类内声明保持完全一致(包括noexcept、const限定符),否则编译器当两个不同函数处理 - 移动函数加
noexcept很关键:MyClass(MyClass&&) noexcept =default;,否则std::vector可能放弃移动而降级为拷贝 - 继承体系里,基类用
=default的析构函数若非virtual,派生类仍可能因多态删除引发未定义行为——该virtual还得自己加


















