这道题考察了赋值运算符函数,考虑四点:
1:返回值类型为引用类型;
2:传入参数声明为常量引用,这样做的好处是避免无谓消耗:如果参数不是引用而是实例,那么从形参到实参会调用一次复制构造函数,降低了代码效率;
3:给实例分配新内存之前,要释放实例自身占据的内存,否则将造成内存泄露;
4:要考虑传入的参数和*this是否是同一个实例。
代码如下:
#include<iostream>
#include <string>
using namespace std;
class CMyString
{
public:
CMyString(char* pdata=nullptr);
CMyString(const CMyString& str);
CMyString& operator=(const CMyString &str);
~CMyString(){delete[] m_pData;}
void print(){printf("%s\n",m_pData);}
private:
char* m_pData;
};
CMyString::CMyString(char* pdata)
{
if (pdata==nullptr)
{
m_pData=nullptr;
return;
}
m_pData=new char[strlen(pdata)+1];
strcpy(m_pData,pdata);
}
CMyString::CMyString(const CMyString& str)
{
m_pData=new char[strlen(str.m_pData)+1];
strcpy(m_pData,str.m_pData);
}
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;
//能实现功能,但是没有考虑到异常安全
/*if (this==&str)
{
return *this;
}
else
{
delete[] m_pData;
m_pData=nullptr;
m_pData=new char[strlen(str.m_pData)+1];
strcpy(m_pData,str.m_pData);
return *this;
}*/
}
int main()
{
printf("test01\n");
char text[]="add";
CMyString a(text);
CMyString b,c;
//连续赋值
c=b=a;
c.print();
//赋值给自己
c=c;
c.print();
cin.get();
}
这里的赋值运算符函数写了两种,下面那个没有考虑异常安全,在new char[]的过程中,有可能因为内存不足抛出异常,而在new上面又是delete[]操作,这样m_pData就成为了空指针,容易导致程序奔溃。
有两种思路解决这个问题
第一种:先new分配新内容再delete,这样就算分配内存失败也不会修改CMyString的实例;
char * pTemp = new char[strlen(str.m_pData) + 1];
delete[] m_pData;
m_pData = NULL;
m_pData = pTemp;
strcpy(m_pData, str.m_pData);
return *this;
第二种:程序中的上面那个写法。strTemp是局部变量,if函数执行完成后变自动释放,strTemp.m_pData所指向的内存也自动释放,因此无需delete
if (this!=&str)
{
CMyString strTemp(str);
char* pTemp=strTemp.m_pData;
strTemp.m_pData=m_pData;
m_pData=pTemp;
}
return *this;