C++赋值运算符函数

时间:2022-07-29 01:36:14

编写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名企面试官精讲编程题》