【剣指offer】面接問題1:賦値演算子関数【C++バージョン】


総括した部分のテーマの構想とコードは、完備しなければならない.【剣指offer-第2版】部分テーマと解答【C++バージョン】
タイトル:
代入演算子関数
タイプCMyStringの宣言は次のとおりです.このタイプに代入演算子関数を追加してください.
class CMyString {
public:
    //    
    CMyString(char *pData = nullptr);
    //      
    CMyString(const CMyString &str);
    //       
    CMyString &operator=(const CMyString &str);
private:
    char *m_pData;
};

問題解決の考え方:
1.初級の場合:
1).戻りタイプは、そのタイプの参照であり、関数が終了する前にインスタンス自体の参照を返す(これにより連続的な付与が許可される).パラメータをこのタイプの定数参照として宣言し、不要なコピー構造を避ける.3).必要に応じて、インスタンス自体がすでに持っているメモリを解放する必要があります.4).入力されたパラメータと現在のインスタンス(*this)が同じインスタンスであるかどうかを判断する(自己付与を判断する場合).
2.上級プログラマーは、メモリ不足でnewが失敗するかどうかを判断する必要があります.解決策は2つあります.
1).まずnewが空間を割り当ててからdeleteが解放されます.割り当て空間が成功した後にのみ既存のコンテンツを解放します.すなわち、割り当てが失敗した場合、既存のコンテンツを保存することを保証することができます.2).コピーコンストラクション関数を使用して一時インスタンスを作成し、一時インスタンスとそれ自体を交換します.一時インスタンスは、割り当て関数をコピーした後に自動的に解析され、一時インスタンスのメモリ割り当てに失敗した場合も、元のコンテンツは変更されません.
また、コピーコンストラクタについては、次の手順に従います.
1.実は構造関数ですが、パラメータはこのタイプ自体です.2.コピーは元の変数に影響しないため、constの参照になります.リファレンスを使用しない場合、コンストラクション関数は無限にループされます.3.新しい変数に値を割り当てるときに参照されます.割り当て演算子は、既存の変数に値を割り当てる場合に使用されます.
方法一【C++バージョン】
CMyString.h   

#pragma once

class CMyString {
public:
    CMyString(char *pData = nullptr);
    //      
    //         ,         ,        
    CMyString(const CMyString &);
    ~CMyString();
    CMyString &operator=(const CMyString &str);
    char *getData();
private:
    char *m_pData;
};
CMyString.cpp   

#include "CMyString.h"
#include 
#include 

using namespace std;

CMyString::CMyString(char *pData){
    m_pData = new char[strlen(pData) + 1];
    strcpy(m_pData, pData);
}

CMyString::~CMyString() {
    if (m_pData) {
        delete[] m_pData;
        m_pData = nullptr;
    }
}

//      
//      const   ,          ,       ,            
CMyString::CMyString(const CMyString &str) {
    cout << "        !" << endl;
    m_pData = new char[strlen(str.m_pData) + 1];
    strcpy(m_pData, str.m_pData);
}

//       
CMyString &CMyString::operator=(const CMyString &str) {
    cout << "         !" << endl;
    if (this == &str) {
        //        
        return *this;
    }

    //       
    if (m_pData) {
        delete[] m_pData;
        m_pData = nullptr;
    }

    m_pData = new char[strlen(str.m_pData) + 1];
    strcpy(m_pData, str.m_pData);

    return *this;
}

char *CMyString::getData() {
    return m_pData;
}
main.cpp      

#include "CMyString.h"
#include 
#include 

using namespace std;

int main()
{
    char *tmp = "hello world";
    CMyString myStr(tmp);

    cout << "myStr: " << myStr.getData() << endl;

    CMyString otherOne = myStr;

    cout << "otherOne: " << otherOne.getData() << endl;

    char *tmp2 = "show the difference.";
    CMyString myStr2(tmp2);
    cout << "myStr2: " << myStr2.getData() << endl;

    myStr2 = otherOne;
    cout << "myStr2 after operator \"=\": " << myStr2.getData() << endl;

    system("pause");
    return 0;
}
myStr: hello world
        !
otherOne: hello world
myStr2: show the difference.
         !
myStr2 after operator "=": hello world
       . . .

方法2:new分配空間が十分であるかどうかを考慮する【C++バージョン】
CMyString &CMyString::operator=(const CMyString &str) {
    if (this != &str) {
        //        
        CMyString strTmp(str);

        char *pTmp = strTmp.m_pData;
        strTmp.m_pData = m_pData;
        m_pData = pTmp;
    }

    return *this;
}