3.异常安全的赋值运算符重载

一、题目

  如下为类型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
", 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]; // 加一,为存放字符串的结束符''
 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的内存。这样就能自动释放内存了。同时也是异常安全的。

  

原文地址:https://www.cnblogs.com/wangjzh/p/4355514.html