题目要求为下面一个类实现一个赋值运算符的函数:
class CMyString {
public:
CMyString(char* pData = NULL);
CMyString(const CMyString& str);
~CMyString();
private:
char* m_pData;
};
我们要实现任意的一个类的赋值运算符函数,都要注意一些方面:
- 返回值类型是类引用,返回*this
- 参数类型是常量引用
- 如果有动态内存,是否发生内存泄露
- 如果传入参数为调用者自身,直接返回
书上的解法给的确实很完备,而且后来用了一种巧妙的方法让程序自动释放内存。但我觉得重点是他提到的异常安全性的处理,这里的话如果我们在new的时候内存不够,而我们又已经delete掉原来的内存,就会导致调用者的内存被无故释放了;所以书上采用新建临时变量,然后再让*this的m_pData指针和临时变量的m_pDatam做交换,就算如果新建临时变量的时候内存不够,也可以保证调用者调用失败也没有被改变。
但是我想了一下,异常安全性的思想是很宝贵,但是实现起来其实可以用try catch这样也很直观:
CMyString & CMyString::operator = (const CMyString& str) {
if (this == &str) {
return *this;
}
try{
delete [] this->m_pData;
this->m_pData = new char [strlen(str.m_pData) + 1];
strcpy(this->m_pData, str.m_pData);
} catch(std::exception& e) {
std::cout << e.what() << std::endl;
std::cout << "申请内存错误,赋值失败,返回原对象" << std::endl;
}
return *this;
}
这里提到赋值运算符的话,就要顺便说一下拷贝构造函数;
CMyString s2;
CMyString s1 = s2; //这一行其实调用的是拷贝构造函数
区别就在于,拷贝构造函数的调用,之前是没有对象的,所以如果有动态内存,拷贝构造函数肯定不会先去delete;
而赋值运算符是讲一个对象赋给另外一个对象,之前是有对象的,这么一来就有了对之前对象的处理。
我把所有函数的实现和一些注意事项放在这里啦~
https://github.com/preke/AimToOffer/blob/master/01.c%2B%2B