目录
题目描述
如下类型CMyString的声明,请为该类型添加赋值运算符函数。
class CMyString {
public:
CMyString(char* pData = nullptr);
CMyString(const CMyString& str);
~CMyString(void);
private:
char* m_pData;
};
解题思路
1. 返回值的类型需声明为该类型的引用,并在函数结束前返回该实例自身的引用(*this)。这样才可以允许连续赋值。
2. 传入的参数类型需声明为常量引用。如果传入参数是实例,从形参到实参就会调用一次复制构造函数,造成无谓的消耗;同时,赋值运算符函数内不会改变传入实例的状态,故应在传入的引用参数上加const。
3. 在分配新内存前,要释放自身已有空间,避免内存泄漏。传入参数的数据大小与当前实例已有空间大小未必一致,故需释放自身已有空间并重新分配内存。
4. 需要判断传入的参数和当前的实例(*this)是不是同一个实例。如果是,则不赋值,直接返回。倘若不判断,在释放自身内存时就会导致严重问题。
5. 需要保证重新分配内存失败时,原有实例不会被修改。一种办法是,先用new分配新内容,成功后再delete已有内容;另一种办法是,先创建一个临时实例,再交换临时实例和原有实例。
经典解法
没有考虑异常安全性。
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;
}
高级解法
针对问题:如果提前释放内存后再申请内存时,内存不足抛出异常,原来的实例将变成空指针,从而很容易导致程序崩溃。
解决办法:先创建一个临时实例,再交换临时实例和原来的实例。此时,倘若内存分配失败,原来的实例不会被修改。临时实例出if作用域便自动析构,就完成了内存释放。
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;
}
知识点
- C++基础语法:运算符函数、常量引用等
- 内存泄漏:C/C++内存泄漏-CSDN博客
- 异常安全性