一、为什么需要赋值运算符重载?
使用编译器默认生成的赋值运算符重载,当对象有申请动态分配的资源时,会带来两个问题。
二、浅拷贝的两个致命问题
1. 同一个空间析构释放两次
赋值运算符重载中深拷贝用来解决浅拷贝带来的危害。如果对象在堆区申请内存,赋值运算符重载浅拷贝会造成同一块内存被释放两次。
2. 内存泄漏
被赋值的那个对象中的_str 指向了赋值对象_str 指向的空间,而被赋值的对象_str 原先的空间没有指针指向,造成内存泄漏。因此赋值运算符重载对于有动态分配资源的对象进行赋值操作时,需要深拷贝来解决问题。
形象比喻:在 C++ 中,当类包含动态分配的资源时,默认的赋值操作(浅拷贝)会带来严重问题。想象一下两个人共用一个碗吃饭,当其中一个人决定换碗时,如果处理不当,可能会把另一个人的饭碗也砸了。这就是我们需要自定义赋值运算符重载的原因。
三、赋值运算符重载传统写法:粗暴的'砸碗'操作
传统写法是自己完成开空间,拷贝内容到新空间,释放旧空间,然后_str 指向新空间,并且更新成员变量,也就是_size 和_capacity。
1、'砸碗'比喻解析
场景:A = B(赋值操作)
买新碗:
new char[]创建新内存 盛饭:memcpy复制 B 的数据到新内存 砸旧碗:delete[] _str释放 A 的旧内存 用新碗:_str = temp让 A 指向新内存
自赋值的危险:A = A
A 和 B 其实是同一个人,共用同一个碗。买新碗、盛饭都正常。**砸旧碗时把唯一的碗砸了!**后续操作无法进行。
string& operator=(const string& s) {
if (this != &s) { // 自赋值检查:确保不是自己给自己赋值
char* temp = new char[s._capacity + 1]; // 1. 买新碗
memcpy(temp, s._str, s._size + 1); // 2. 把旧碗的饭盛到新碗
delete[] _str; // 3. 砸旧碗
_str = temp; // 4. 用新碗
_size = s._size;
_capacity = s._capacity;
}
return *this;
}
2、赋值运算符重载传统写法 - 自赋值问题
我们来看传统写法中自赋值的问题。假设我们有一个字符串对象,我们将其赋值给自己,即 str = str;。在传统写法中,如果没有自赋值检查,代码会这样执行:
分配新内存:
char* temp = new char[s._capacity + 1];复制数据: 释放旧内存: 更新指针:


