C++赋值运算符函数

编写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] = '';
    } 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
", 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名企面试官精讲编程题》

原文地址:https://www.cnblogs.com/RDaneelOlivaw/p/7344435.html