面试题1:赋值运算符函数

题目:如下为类型CMyString的声明,请为该类型添加赋值运算符函数。

class CMyString
{
  public:
    CMyString(char* pData = NULL);
    CMyString(const CMyString&str);
    ~CMyString(void);
  private:
    char* m_pData;
};

考点:

  • 是否把返回值的类型声明为该类型的引用,并在函数结束前返回该实例自身的引用(*this)。只有这样才允许连续赋值。
  • 是否把传入的参数的类型声明为常量引用。避免改变实例状态以及参数拷贝造成的无谓消耗。
  • 是否释放实例自身已有的内存。避免内存泄露。
  • 是否判断传入的参数和当前的实例是否为同一个实例。

初级程序员解法:

CMyString& CMyString::operator = (const CMyString&str)
{
  if (this == &str)
    return *this;
  delete []m_pData;
  m_pData = NULL;
      m_pData = new char[strlen(str.mpData)+1];
  strcpy(m_pData, str.m_pData);
  return *this;
}

上述代码存在的问题:

先释放内存,再分配新的内存,一旦新的内存分配失败,则m_pData将是一个空指针,CMyString的实例不再保持有效状态,违背了异常安全性原则。

解决方法1:先判断内存是否分配成功,再释放原有内存。

解决方法2:先创建一个临时实例,再交换临时实例和原来的实例。

 1 CMyString& CMyString::operator = (const CMyString&str)
 2 {
 3   if (this != &str)
 4   {
 5           CMyString strTemp(str);
 6          char * temp = strTemp.m_pData;
 7          strTemp.m_pData = m_pData;
 8          m_pData = temp;
 9      }
10   return *this;
11 }    

分析:我们的目的是要释放原来内存,开辟新的内存,同时遵守异常安全性原则。在上述代码中,先创建一个临时变量strTemp,在此过程中会通过拷贝构造函数开辟新的内存,然后交换strTemp与m_pData的指针。由于strTemp是临时变量,作用域在if内,因此当程序运行到if的外面时就会调用该变量的析构函数释放strTemp.m_pData所指向的内存。同时,如果由于内存不足抛出异常,也不会对原来实例的状态产生影响,也就保证了异常安全性原则。

原文地址:https://www.cnblogs.com/happygirl-zjj/p/4609825.html