String類 (淺拷貝/深拷貝/寫時拷貝)

淺拷貝是指當對象的字段值被拷貝時,字段引用的對象不會被拷貝。例如,如果一個對象有一個指向字符串的字段,並且我們對該對象做了一個淺拷貝,那麼兩個對象將引用同一個字符串。

存在問題:
如果源程序中沒有顯示定義拷貝構造函數,在進行對象的拷貝時,將調用系統默認的拷貝構造函數,這就使得兩個對象指向了同一資源,而析構函數又在對象生命週期結束後可以釋放空間,勢必會兩次返還空間,編譯器就會報錯。

這時就需要用到深拷貝了。

深拷貝的兩種版本:

#define  _CRT_SECURE_NO_WARNINGS 1  

#include<iostream>
using namespace std;

//#if 0
class String
{
public:
    String(char *pStr = "")   //構造函數
    {
        if (NULL == pStr)
        {
            _pStr = new char[1];
            *_pStr = 0;
        }
        else
        {
            _pStr = new char[strlen(pStr) + 1];
            strcpy(_pStr, pStr);
        }
    }

    //簡潔版

    ////拷貝構造函數 1
    //String(const String &s)
    //  :_pStr(new char[strlen(s._pStr) + 1])
    //{
    //  String temp(s._pStr);
    //  swap(_pStr, temp._pStr);
    //}


    ////拷貝構造函數 2
    //String(const String &s)
    //  :_pStr(NULL)
    //{
    //  _pStr = new char[1];
    //  String temp(s._pStr);
    //  swap(_pStr, temp._pStr);
    //}

    //普通版
    String(const String &s)
        :_pStr(new char[strlen(s._pStr) + 1])
    {
        strcpy(_pStr, s._pStr);
    }



    //賦值運算符重載 

    /*
    //由於pTemp在棧上,出了函數將銷燬,故錯誤
    String &operator=(const String &s)//賦值運算符重載
    {
    if (this != &s)
    {
    char *pTemp = new char[strlen(s._pStr) + 1];//  pTemp在棧上
    strcpy_s(pTemp, strlen(s._pStr), s._pStr);
    //strcpy_s(_pStr, strlen(pStr), pStr);
    delete[] _pStr;
    _pStr = pTemp;
    }
    return *this;

    }
    */
    //賦值運算符重載 1
    /*
    String &operator=(const String &s)
    {
    //if (this != &s)   賦值運算符重載的反例,會造成一塊空間多次釋放
    //{
    //  _pStr = s._pStr;
    //}
    //return *this;
    if (this != &s)
    {
    String temp(s._pStr);//用S裏面的字符串構造一個臨時的temp
    swap(_pStr, temp._pStr);//交換兩個指針
    }
    return *this;
    }
    */

    //賦值運算符重載 2
    String& operator=(const String& pStr)
    {
        if (this != &pStr)
        {
            //防止new開闢內存失敗,丟失原來內存  
            char* ptr = new char[strlen(pStr._pStr) + 1];
            strcpy(ptr, pStr._pStr);
            delete[]_pStr;
            _pStr = ptr;
        }
        return *this;
    }


    ~String()    //析構函數
    {
        if (this != NULL)
        {
            delete[] _pStr;
            _pStr = NULL;//可有可無
        }
    }
    friend ostream& operator<<(ostream & _cout, const String&pStr);
private:
    char *_pStr;

};
//輸出流重載
ostream& operator<<(ostream & _cout, const String&pStr)
{
    _cout << pStr._pStr << endl;
    return _cout;
}
void FunTest1()
{
    String s1("hello");
    cout << "s1=" << s1 << endl;
    String s2(s1);   //調用拷貝構造函數
    cout << "s2=" << s2 << endl;

}

void FunTest2()
{
    String s3("word");
    String s4;
    s4 = s3;         //調用賦值運算符重載
    cout << "s3=" << s3 << endl;
    cout << "s4=" << s4 << endl;
}
int main()
{
    FunTest1();
    FunTest2();
    getchar();
    return 0;
}
//#endif

這裏寫圖片描述

1、開闢兩個空間的計數,代碼如下:

#include<iostream>
using namespace std;

class String
{
public:
    String(const char * pStr = "")//構造函數
        :_pCount(new int(1))  //_pCount初始化爲1
    {
        if (NULL == pStr)
        {
            _pStr = new char[1];
            *_pStr = '\0';
        }
        else
        {
            _pStr = new char[strlen(pStr) + 1];
            strcpy(_pStr, pStr);
        }
    }
    String(const String &s)//拷貝構造函數
        :_pStr(s._pStr)
        , _pCount(s._pCount)
    {
        ++*_pCount;//調用一次拷貝構造函數_pCount++
    }
    //賦值運算符重載
    String & operator = (const String & s)
    {
        if (this != &s)
        {
            if (0 == --*_pCount)
            {
                delete[] _pStr;
                delete _pCount;
            }
            _pStr = s._pStr;
            _pCount = s._pCount;
            ++*_pCount;
        }
    }
    ~String()//調用析構函數時 先--_pCount,判斷是否爲0
    {
        if ((_pStr) && (0 == --*_pCount))
        {
            delete[] _pStr;
            _pStr = NULL;
            delete _pCount;
            _pCount = NULL;
        }
    }
    friend ostream& operator<<(ostream & output, const String &s);
private:
    char * _pStr;
    int * _pCount;
};
ostream& operator<<(ostream & output, const String &s)//輸出流的重載
{
    output << s._pStr << endl;
    return output;
}
void FunTest()
{
    String s1("hello");
    cout << "s1=" << s1 << endl;
    String s2(s1);
    cout << "s2=" << s2 << endl;
    String s3("heihei");
    cout << "s3=" << s3 << endl;
    String s4 = s3;
    cout << "s4=" << s4 << endl;

}
int main()
{
    FunTest();
    getchar();
    return 0;
}

運行結果:
_pCount計數

2、一個空間的計數,代碼如下:

class String
//{
//public:
//  String(char* ptr = NULL)
//  {
//      if (ptr == NULL)
//      {
//          _ptr = new char[5];
//          *(_ptr + 4) = 0;
//      }
//      else
//      {
//          _ptr = new char[strlen(ptr) + 5];
//          strcpy(_ptr + 4, ptr);
//      }
//      *(int*)_ptr = 1;
//  }
//  String(const String& s)
//      :_ptr(s._ptr)
//  {
//      (*(int*)_ptr)++;
//  }
//  String& operator=(const String& s)
//  {
//      if (&s != this)
//      {
//          _ptr = s._ptr;
//          (*(int*)_ptr)++;
//      }
//      return *this;
//  }
//  ~String()
//  {
//      if (--*(int*)_ptr == 0)
//      {
//          delete[] _ptr;
//          _ptr = NULL;
//      }
//  }
//private:
//  char* _ptr;
//};
class String
{
public:
    String(const char* pStr)
    {
        if (pStr == NULL)
            pStr = " ";

        _pStr = new char[strlen(pStr) + 1 + 4];//多開闢4個字節
        _pStr += 4;
        strcpy(_pStr, pStr);
        GetReference() = 1;
    }
    String(const String&s)
        :_pStr(s._pStr)
    {
        ++ GetReference();
    }
    String & operator = (const String & s)
    {
        if (this != &s)
        {
            if (--GetReference() = 0)
            {
                _pStr -= 4;
                delete[] _pStr;

            }
            _pStr = s._pStr;
            ++GetReference();
        }
    }
    ~String()
    {
        if ((--GetReference() == 0) && _pStr)
        {
            _pStr -= 4;
            delete[] _pStr;
            _pStr = NULL;
        }
    }
    friend ostream & operator<<(ostream &output, String &s);
private:
    int& GetReference()
    {
        return *(int*)(_pStr - 4);
    }
    char* _pStr;
};
ostream & operator<<(ostream &output, String &s)
{
    output << s._pStr << endl;
    return output;
}
void FunTest()
{
    String s1("ximenchuixue");
    cout << "s1=" << s1 << endl;
    String s2(s1);
    cout << "s2=" << s2 << endl;
    String s3("sikongzhaixing");
    cout << "s3=" << s3 << endl;
    String s4 = s3;
    cout << "s4=" << s4 << endl;

}
int main()
{
    FunTest();
    getchar();
    return 0;

}

運行結果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章