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

1 赋值运算符函数

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

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

2 基本考察点

  1. 是否把返回值的类型声明为该类型的引用,并在函数结束前返回实例自身的引用(*this)。因为只有返回一个引用时,才可以允许连续赋值。

  2. 是否把传入的参数类型声明为常量引用。同时为了避免在赋值运算内改变传入的实例状态,因此应该加上const

  3. 是否释放实例自身已有内存

  4. 判断传入的参数和当前的实例(*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的内存,相当于自动调用析构函数释放实例的内存。

posted @ 2021-03-10 21:59  一地斜阳  阅读(72)  评论(0)    收藏  举报