拷贝赋值运算符必须显式定义以避免浅拷贝问题,声明为myclass& operator=(const myclass& other),需自赋值检查、深拷贝及异常安全(推荐复制-交换),含不可拷贝成员时应=delete。

拷贝赋值运算符的声明和基本结构
必须显式定义拷贝赋值运算符,当类管理动态资源(如 new 出的内存、文件句柄、socket)时;否则默认生成的浅拷贝会导致双重释放或悬空指针。
它是一个名为 operator= 的非静态成员函数,返回 MyClass&(支持链式赋值),参数为 const MyClass&:
MyClass& operator=(const MyClass& other) {
if (this == &other) return *this; // 自赋值检查
// 释放当前资源
// 深拷贝 other 的资源
return *this;
}
- 不加
const引用参数会拒绝绑定临时对象,失去通用性 - 返回引用而非值,避免无谓拷贝;返回
*this是约定俗成 - 自赋值检查不能省——尤其在“先释放再分配”模式下,
a = a会导致delete后又解引用
常见错误:异常安全与资源泄漏
直接在函数体内 delete 原指针、再 new 分配,一旦 new 抛出异常,对象就处于半销毁状态(资源已释放,新资源未建立),违反强异常安全保证。
- 推荐使用「复制-交换」惯用法(copy-and-swap):接收参数按值传入 → 触发拷贝构造 → 在函数内交换成员 → 离开作用域时旧资源由临时对象析构
- 需要提前定义好拷贝构造函数和
swap()成员(或友元),且swap()必须是noexcept - 若类含不可拷贝成员(如
std::unique_ptr),则拷贝赋值应被删除:MyClass& operator=(const MyClass&) = delete;
与移动赋值运算符共存时的注意事项
当同时定义了移动赋值(MyClass& operator=(MyClass&&)),拷贝赋值仍需保留,因为右值不会绑定到 const MyClass& 参数——但编译器不会自动禁用拷贝赋值,除非你显式 = delete。
- 移动赋值里通常用
std::move转移资源,而拷贝赋值必须深拷贝,二者逻辑不能混用 - 如果只希望支持移动不支持拷贝,记得把拷贝赋值设为
delete,否则用户误写a = b(b 是左值)仍会调用拷贝版本,可能违背设计意图 - 检查是否意外禁用了隐式生成:若定义了任意构造函数(包括移动构造),编译器不再自动生成拷贝赋值,必须手动提供或明确删除
测试时容易忽略的边界场景
光测 a = b 正常还不够,真正暴露问题的是这些用例:
- 自赋值:
a = a;—— 没做地址检查就会崩 - 跨对象赋值后原对象是否仍可用(深拷贝要求)
- 赋值后两个对象修改互不影响(验证是否真深拷贝)
- 在构造失败中途抛异常时,目标对象是否保持有效状态(靠复制-交换可缓解)
涉及裸指针的手动内存管理时,建议优先用 std::vector、std::string 或 std::unique_ptr 替代——它们自带正确的拷贝/移动语义,能大幅降低出错概率。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











