编写assigment赋值运算符函数时需注意几点:
1. 返回值类型声明为该class的引用,为允许连续赋值(如可解析为右结合律的a=b=c),函数结束前应返回对象自身引用(*this);
2. 传入参数类型应声明为该class的常量引用,因为1)如果传入的参数是实例,从形参到实参会调用一次赋值构造函数增大开销 2)加上const关键字避免改变传入参数对应实例;
3. 注意释放该实例自身已有的内存,如果分配新内存前忘记释放已有的内存会造成内存泄漏;
4. 应先判断传入参数对应的实例和*this是否为同一实例,如果相同则直接返回*this,不进行赋值操作。如果对与*this相同的实例进行赋值操作,释放自身内存时也同时会释放传入参数的内存,造成严重问题。
经典解法:先判断传入参数是否为*this,若不是则先释放已有内存,再根据传入的参数分配新内存并对数据进行赋值,返回*this。
CMyString& CMyString::operator=(const CMyString& str) {
if(this == &str)
return *this;
delete []m_pData;
m_pData = NULL;
m_pData = new char[strlen(str.m_pData)+1];
strcpy(m_pData, str.m_pData);
return *this;
}
但此解法仍不具备异常安全性,如果因为分配时内存不足或copy函数抛出异常导致new()异常,持有指针可能会指向已被删除的对象。为让赋值运算符具备异常安全性,可在复制指针所指对象时,先不delete该指针,这样如果new()抛出异常,指针和指针原指的对象能够保持原状。
CMyString& CMyString::operator=(const CMyString& str) {
if(this==&str)
return *this;
char* pOrig = m_pData;
m_pData = new char[strlen(str.m_pData)+1];
strcpy(m_pData, str.m_pData);
delete pOrig;
return *this;
}
此外,还有一个办法是先创建一个临时实例,再交换临时实例和原来的实例,因为临时实例是一个局部变量,程序运行到区块结束就离开了该变量的作用域,临时变量的析构函数被自动调用,其指针指向的内存会被释放,也就释放了原先的m_pData指向的内存。
CMyString& CMyString::operator=(const CMyString& str) {
if(this == &str)
return *this;
CMyString strTemp(str);
char* pTemp = strTemp.m_pData;
strTemp.m_pData = m_pData;
m_pData = pTemp;
return *this;
}
完整代码:
#include <iostream>
#include <stdio.h>
using namespace std;
class CMyString {
public:
CMyString(char* pData = NULL);
CMyString(const CMyString& str);
~CMyString(void);
CMyString& operator=(const CMyString& str);
void print();
private:
char* m_pData;
};
CMyString::CMyString(char* pData) {
if(pData == NULL) {
m_pData = new char[1];
m_pData[0] = '\0';
} else {
int length = strlen(pData);
m_pData = new char[length+1];
strcpy(m_pData, pData);
}
}
CMyString::CMyString(const CMyString& str) {
int length = strlen(str.m_pData);
m_pData = new char[length+1];
strcpy(m_pData, str.m_pData);
}
CMyString::~CMyString(void) {delete []m_pData;}
CMyString& CMyString::operator=(const CMyString& str) {
if(this == &str)
return *this;
CMyString strTemp(str);
char* pTemp = strTemp.m_pData;
strTemp.m_pData = m_pData;
m_pData = pTemp;
return *this;
}
void CMyString::print() {
cout << "The data is ";
printf("%s\n", m_pData);
}
int main() {
char* text="sdlkjfskdfk";
CMyString str1(text);
cout << "str1: ";
str1.print();
CMyString str2(str1);
cout << "-------do str2(str1)--------"<< endl;
cout << "str2: ";
str2.print();
cout << "------------------------------" << endl << endl;
CMyString str3="4534534534dd";
cout << "str1: ";
str1.print();
cout << "str2: ";
str2.print();
cout << "str3: ";
str3.print();
cout << "--------do str1 = str2 = str3 --------" << endl;
str1 = str2 = str3;
cout << "str1: ";
str1.print();
cout << "str2: ";
str2.print();
cout << "str3: ";
str3.print();
cout << "---------------------------------" << endl << endl;
cout << "str1: ";
str1.print();
cout <<"------------do str1 = str1 --------" << endl;
str1 = str1;
cout << "str1: ";
str1.print();
}
参考资料:《剑指offer名企面试官精讲编程题》