面试题1:赋值运算符函数
1 赋值运算符函数
题目:如下为类型CMyString 的声明,请为该类型添加赋值运算符函数
class CMyString
{
public:
CMyString(char*pData = nullptr);
CMyString(const CMyString& str);
~CMystring(void);
private:
char* m_pData;
}
2 基本考察点
-
是否把返回值的类型声明为该类型的引用,并在函数结束前返回实例自身的引用(*this)。因为只有返回一个引用时,才可以允许连续赋值。
-
是否把传入的参数类型声明为常量引用。同时为了避免在赋值运算内改变传入的实例状态,因此应该加上const
-
是否释放实例自身已有内存
-
判断传入的参数和当前的实例(*this)是不是同一个实例,若是不进行赋值操作,否则,当一旦释放自身内存,传入的参数的内存也同时释放了,会因找不到需要赋值的内容了。
3 经典解法
CMyString& CMystring::operator=(const CMyString& str)
{
if(this == &str)
return *this;
delete []m_pData;
m_pData=nullptr;
m_pData = new char[strlen(str.m_pData)+1];
strcpy(m_pData,str.m_pData);
return *this;
}
4 进阶解法
经典解法问题,由于先释放了实例m_pData的内存,若接下来内存不足导致 new char 抛出异常时,则m_pData将是一个空指针。CMyString的实例不在保持有效状态,违背了异常安全性原则。
两种解决方法:
1.我们先用new 分配新内容,再用delete释放已有的内容。当内存分配失败的时候,我们能确保CMyString的实例不会被修改。
2.先创建临时实例,再交换临时实例和原来的实例。
代码如下:
CMyString& CMystring::operator=(const CMyString& str)
{
if(this != &str)
{
CMyString strTemp(str);
char* pTemp = strTemp.m_pData;
strTemp.m_pData = m_pData;
m_pData = pTemp;
}
return *this;
}
由于strTemp是一个局部变量,当程序运行到if外面的时候,超出变量作用域,就会自动调用strTemp的析构函数,把strTemp.m_pData指向的内存释放掉。由于strTemp.m_pData指向的内存就是实例之前m_pData的内存,相当于自动调用析构函数释放实例的内存。

浙公网安备 33010602011771号