赋值运算符

C++ 中,为什么要重写赋值运算符?

为什么需要重写

  • 系统已经提供了默认的拷贝构造函数和赋值运算符,但都是浅拷贝。
  • 有指针的情况下,一般我们需要重写赋值运算符和拷贝构造函数。

案例

注意异常安全和自赋值问题:

//非异常安全版本 CMyString& CMyString::operator =(const CMyString &str) { if(this == &str) return *this; delete []m_pData; m_pData = NULL; m_pData = new char[strlen(str.m_pData) + 1]; strcpy(m_pData, str.m_pData); return *this; }

我们知道,在分配内存时有可能发生异常。当执行语句:

new char[strlen(str.m_pData) + 1]

发生异常时,程序将从该赋值运算符的重载函数退出不再执行。注意到这个时候语句 delete []m_pData 已经执行了。也就是说赋值操作没有完成,但原来对象的状态已经改变。

//异常安全版本 CMyString& CMyString::operator =(const CMyString &str) { if(this != &str) { m_pData = new char[strlen(str.m_pData) + 1]; delete []m_pData; m_pData = NULL; return *this; } return *this; }

异常安全版本, 基于拷贝交换技术

CMyString& CMyString::operator =(const CMyString str) //参数是非引用吧 { if(this != &str) { char* pTemp = str.m_pData; str.m_pData = m_pData; m_pData = pTemp; } return *this; }

该方案通过调用构造拷贝函数创建一个临时对象来分配内存。此时即使发生异常,对原来对象的状态没有影响。

交换临时对象和需要赋值的对象的字符串指针之后,由于临时对象的生命周期结束,自动调用其析构函数释放需赋值对象的原来的字符串空间。整个函数不需要显式用到 new、delete,内存的分配和释放都自动完成,因此代码显得比较优雅。