更多剑指offer习题请点击:《剑指offer》(第二版)题集目录索引
一、题目
如下为类型CMyString的声明,请为该类型添加赋值运算符函数。
class CMyString
{
public:
CMyString(char* pData = nullptr);
CMyString(const CMyString& str);
~CMyString(void);
CMyString& operator = (const CMyString& str);
void Print();
private:
char* m_pData;
};
二、传统写法
CMyString& CMyString::operator = (const CMyString& str) //传统写法
{
// 1.检查自赋值
if (this != &str)
{
// 2.分配新的内存资源,并复制内容
char* tmp = new char[strlen(str.m_pData) + 1];
strcpy(tmp, str.m_pData);
// 3.释放原有的内存资源
delete[]m_pData;
m_pData = tmp;
}
// 4.返回本对象的使用
return *this;
}
1. 注意要点
检查自赋值。防止出现
a = a
或者p = &a; a = *p
这种代码。注意不要写成if (*this != str)
。分配新的内存资源,并复制字符串。如果是先释放了原有的内存资源,那么若后来的内存分配失败,那就惨了!所以先分配内存给一个临时变量,万一分配失败(抛出异常)也不会改变
this
对象,这是为了实现异常安全。用
delete[]
释放原有内存资源。现在不释放,后面就没机会释放了,会造成内存泄漏。返回本对象的引用,是为了实现如
a = b = c;
这样的链式表达式。注意不能返回str
,因为它可能是个临时对象,在赋值结束后马上消失,那么return other;
返回的将是垃圾。
三、现代写法
void CMyString::Swap(CMyString& other)
{
swap(m_pData, other.m_pData);
}
CMyString& CMyString::operator = (CMyString str) //现代写法
{
str.Swap(*this); //直接与临时对象进行交换,异常安全的。
return *this;
}
四、测试代码
void Test1()
{
printf("Test1 begins:\n");
char* text = "Hello world";
CMyString str1(text);
CMyString str2;
str2 = str1;
printf("The expected result is: %s.\n", text);
printf("The actual result is: ");
str2.Print();
printf("\n\n");
}
// 赋值给自己
void Test2()
{
printf("Test2 begins:\n");
char* text = "Hello world";
CMyString str1(text);
str1 = str1;
printf("The expected result is: %s.\n", text);
printf("The actual result is: ");
str1.Print();
printf("\n\n");
}
// 连续赋值
void Test3()
{
printf("Test3 begins:\n");
char* text = "Hello world";
CMyString str1(text);
CMyString str2, str3;
str3 = str2 = str1;
printf("The expected result is: %s.\n", text);
printf("The actual result is: ");
str2.Print();
printf("\n\n");
printf("The expected result is: %s.\n", text);
printf("The actual result is: ");
str3.Print();
printf("\n\n");
}
int main(int argc, char* argv[])
{
Test1();
Test2();
Test3();
system("pause");
return 0;
}