一、题目
如下为类型CMyString,请为该类型添加赋值运算符函数。
1 class CMyString 2 { 3 public: 4 CMyString(char* pData) 5 { 6 m_pData = new char[strlen(pData) + 1]; 7 strcpy(m_pData, pData); 8 } 9 10 CMyString(): m_pData(NULL) {} 11 12 13 CMyString(const CMyString& str); 14 15 ~CMyString() 16 { 17 delete []m_pData; 18 } 19 20 CMyString& operator =(const CMyString& str); 21 22 void Print() const 23 { 24 printf("%s\n", m_pData); 25 } 26 27 28 private: 29 char* m_pData; 30 };
二、经典解法
经典解法代码实现如下:
1 CMyString& CMyString::operator =(const CMyString &str) 2 { 3 // 自身赋值 4 if (this == &str) 5 return *this; 6 7 8 m_pData = new char[strlen(str.m_pData) + 1]; // 加一,为存放字符串的结束符‘\0‘ 9 strcpy(m_pData, str.m_pData); 10 11 return *this; 12 }
这是一个经典的解法,为了防止自身赋值,先判断复制对象,是否是自身,如果是,则什么都不做。这个方法可以应对常规的情况。但是,其没有考虑异常安全。在这里的
new char[],可能会由于内存不足导致其抛出异常。
三、考虑异常安全的解法
实现代码如下:
1 CMyString& CMyString::operator =(const CMyString &str) 2 { 3 if (this != &str) 4 { 5 CMyString strTemp(str); 6 7 char* pTemp = strTemp.m_pData; 8 strTemp.m_pData = m_pData; 9 m_pData = pTemp; 10 } 11 12 return *this; 13 }
在该赋值函数中,如果判断不是自身赋值,那么先用拷贝构造函数以str构造一个临时对象strTemp,此时对于char的内存分配转移到临时对象的拷贝构造函数中,如果抛出异常,那么对于该实例本身来说,没有任何改变,不影响该实例本身的使用。如果临时对象没有出异常,那么将实例自身的m_pData和strTemp.m_pData交换,由于strTemp是临时对象,在作用域结束时,自动调用析构函数,释放内存,而此时的strTemp的m_pData已经指向了原实例的m_pData的内存。这样就能自动释放内存了。同时也是异常安全的。
时间: 2024-10-17 10:24:08