面试题1
题目:如下为Cstring的声明,请为该类型添加赋值运算符函数
class CMyString{
public:
CMyString(char *pData = NULL);
CMyString(const CMyString &str);
~CMyString(void);
private:
char * m_pData;
};
首先都需要考虑的解法是否都满足:str1 = str2 = str3;
再考虑安全性及优化;
解法一:
书上解法(《visual 2012 入门经典》),根据《剑指offer》解析:这种解法没有考虑到异常安全性;因为当计算机内存不足的情况,但是我们已经在之前释放了m_pData的内存,而这时我们分配内存,就会使得m_pData为空指针。那么就会抛出异常;
CMyString& CMyString::operator = (const CMyString &str){
if (this != &str){
delete[] m_pData;
m_pData = NULL;
m_pData = new char[strlen(str.m_pData) + 1];
strcpy_s(this->m_pData, strlen(str.m_pData) + 1, str.m_pData);
}
return *this;
}
解法二:
《剑指offer》上的描述,个人理解如下:我们使用一个临时实例strTemp作为临时用于存储str实例。这样就可以避免解法一因内存不足导致异常的问题。因为我们在创建strTemp时初始为我们用于赋值的实例。这样就可以理解解法一中分配内存给m_pData;由于CMyString中需要赋值的变量m_pData为指针。因此创建一个临时指针。用于保存strTemp.m_pData所指向的内存空间(str.m_pData),再将strTemp.m_pData指向m_pData之前所指向的内存。最后将m_pData指向保存临时赋值值的临时指针pTemp中。就完成了赋值。而由于strTemp是临时变量。那么在执行完if语句时,将会释放内存(可以理解为解法一种delete[]m_pData,就是this指针之前所指向的内存空间,因为按照上述描述,strTemp.m_pData指向的就是那个空间,this指针指向的就是strTemp.m_pData新建的内存(pTemp),在这里如果不再使用一个pTemp保存的话,那么随着strTemp调用析构函数释放内存时,this指针所指向的内存也会被释放)。有点拗口,好好理解。
换言之:
假设初始时str.m_pData指向空间(内存)为A,str.m_pData指针为a;strTemp.m_pData指向空间为B,strTemp.m_pData为指针b;m_pData(this.m_pData)指向空间为C,m_pData指针为c;ptemp指向空间为D,ptemp指针为d。
strTemp.m_pData = str.m_pData (新建内存(new):a->B);
ptemp-> strTemp.m_pData (d->A == d->B);
strTemp.m_pData = m_pData (a->C)
m_pData = ptemp; (c-> D=====c->B);
~CMyString() (strTemp.m_pData,释放内存,删除的内存为C);
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;
}