剑指offer(典型编程题)笔记一
面试题一
题目:为下面的类型添加赋值运算符函数
class CMyString
{
public:
CMyString(char* pData = nullptr);
CMyString(const CMyString& str);
~CMyString(void);
CMyString& operator = (const CMyString& str);
void Print();
private:
char* m_pData;
};
注意点:
- 返回值是否为该类型的引用:函数返回值要返回自身的引用(*this)。只有这样才可以连续赋值。
- 传入的参数类型是否为引用:即在传入的参数前面加上const关键字,避免调用复制构造函数,可以提高代码效率。
- 是否释放实例本身的内存:若忘记在分配新内存志强忘记释放自身的空间,程序将会出现内存泄漏。
- 传入后判断当前实例与传入参数是不是同一个:如果不实现判断,若为同一个,将导致内存释放时全都被释放了。
写出函数
CMyString& CMyString::operator = (const CMyString& str)
{
if(this == &str) //如果是自己给自己赋值,直接返回自身
return *this;
delete []m_pData; //删除原来的值
m_pData = nullptr; // 确保 m_pData 不再指向任何已删除的内存区域
m_pData = new char[strlen(str.m_pData) + 1]; //创建比传入实例大小多一的数组
strcpy(m_pData, str.m_pData);//将数组中的内容拷贝过去
return *this;
}
进阶版
在上面的函数中,在分配内存之前先释放了m_pData的内存,如果因为内存不足导致new char失败,将很容易导致程序崩溃(虽然现在电脑一般不会内存不足),这违反了异常安全性原则。
我们有两种方法可以实现异常安全性:
- 先new分配内容,分配成功后再delete释放已有内容。
- 创建一个临时实例,再交换临时实例和原来的实例。
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;
}
在新的代码中,如果在构造函数中用new分配内存时如果内存不足会抛出异常。

浙公网安备 33010602011771号