C++编译器会隐式生成public、inline、非虚的operator=,执行逐成员浅拷贝,但不处理自我赋值和资源管理;需用= delete在类内声明禁用,并注意匹配参数类型、返回类型及移动语义的协同。

为什么 operator= 会被自动生成?
C++ 编译器会在你没显式定义 operator= 时,悄悄合成一个默认的赋值运算符——前提是类中所有成员都支持赋值。这个隐式生成的版本是 public、inline、非虚的,执行的是逐成员浅拷贝。它不检查自我赋值,也不处理资源管理(比如指针、文件句柄),所以一旦类里有动态内存或独占资源,就极易出问题。
用 = delete 禁用赋值的正确写法
在类内声明 operator= 并加上 = delete,就能彻底阻止编译器生成和用户调用该函数:
class NonCopyable {
public:
NonCopyable() = default;
NonCopyable(const NonCopyable&) = delete; // 禁用拷贝构造
NonCopyable& operator=(const NonCopyable&) = delete; // 禁用赋值
};
注意几点:
-
= delete必须写在类定义内部,不能只在类外声明再 delete - 参数类型要匹配:通常用
const T&,如果禁用右值赋值还要额外加T&&版本 - 返回类型必须是
T&(或const T&),否则不是赋值运算符重载,= delete无效 - 即使只禁用拷贝赋值,移动赋值仍可能被隐式生成,需一并
= delete或显式定义
什么时候只禁用赋值但不禁用拷贝构造?
极少见,但存在:比如某个类允许创建副本(拷贝构造),但副本一旦生成就不允许再被覆盖(赋值)。这时只删 operator= 即可:
立即学习“C++免费学习笔记(深入)”;
class ReadOnlyCopy {
std::vector<int> data_;
public:
ReadOnlyCopy(const ReadOnlyCopy&) = default; // 允许拷贝构造
ReadOnlyCopy& operator=(const ReadOnlyCopy&) = delete; // 但禁止后续赋值
};
这种设计容易引发混淆,因为用户会预期“能拷贝就能赋值”。除非有强语义约束(如封装了只读映射或不可变视图),否则建议统一禁用或统一启用。
禁用后遇到的典型编译错误和应对
一旦 operator= 被 = delete,以下代码都会报错:
-
obj1 = obj2;→ 错误信息类似:use of deleted function 'T& T::operator=(const T&)' -
std::vector<t> v(10);</t>→ 因 vector 内部需要赋值初始化元素而失败 - 类成员含该类型时,外围类的默认赋值也会被隐式删除(链式传染)
解决方法不是绕过 = delete,而是检查设计意图:
- 若确实不该赋值,改用
std::move+ 移动语义(记得也禁用或定义移动赋值) - 若容器必需,改用
std::vector<:unique_ptr>></:unique_ptr>或其他间接持有方式 - 若成员变量导致外围类被“感染”,需手动定义外围类的
operator=并跳过该成员(或用mutable+ 自定义逻辑)
最常被忽略的是:禁用赋值后,类自动失去可复制性,连带影响标准容器、算法、lambda 捕获等——这些地方不会报“赋值错误”,而是报“类型不满足 CopyAssignable”之类更模糊的约束失败。


















