1. 程式人生 > >【C++】c++String類淺拷貝、深拷貝

【C++】c++String類淺拷貝、深拷貝

在瞭解深拷貝以及寫時拷貝之前,我們先來了解什麼是淺拷貝,看下面程式碼:

class String
{
public:
    String(char* ptr = "")
        :_ptr(new char[strlen(ptr)+1])
    {
        if (_ptr != NULL)//空間開闢成功
        {
            strcpy(_ptr, ptr);
        }
    }
    String(const String& s)
        :_ptr(s._ptr)//直接賦值
    {}
    String& operator
= (const String& s) { if (this != &s) { delete[] _ptr; _ptr = s._ptr;//直接賦值 } return *this; } ~String() { if (_ptr) { delete[]_ptr; } } private: char* _ptr; };

如下:s1、s2、s3是String類的三個物件,執行下列程式碼,目的是讓s1、s2、s3在各自的記憶體空間記憶體放著字串”sulijuan“,但卻事與願違。

String s1("sulijuan");
String s2(s1);
String s3;
s3 = s1;

可以通過除錯看到最後s1、s2、s3都指向了同一塊空間:

這裡寫圖片描述

執行過程如下:

這裡寫圖片描述

那麼可想而知,最後釋放物件的時候,理應呼叫三次解構函式來釋放三個物件,s3最先被釋放,當s3被釋放了以後,同時把s1、s2指向的空間一起釋放了,當再次呼叫解構函式想釋放s2時,程式崩潰了~因為s2物件的_ptr指標指向的空間已經還給了作業系統,試圖去釋放一個不屬於你的空間必然崩潰~~~~~~~~

.為了解決淺拷貝的問題,引入了深拷貝。。。。。。。。

淺拷貝是多個物件指向了同一塊空間,導致最後釋放空間出現了問題;那麼深拷貝俗一點講就是讓每個物件對應一塊空間,各自管各自的空間,互不影響,最後釋放各自的空間。

程式碼如下:

class String
{
public:
    String(char* ptr = "")           //建構函式
        :_ptr(new char[strlen(ptr)+1])
    {
        if (_ptr)
        {
            strcpy(_ptr, ptr);
        }
    }
    String(const String& s)
        :_ptr(new char[strlen(s._ptr)+1])//另外開闢空間
    {
        strcpy(_ptr, s._ptr);
    }
    String& operator= (const String& s)
    {
        if (this != &s)
        {
            delete[] _ptr;
            _ptr = new char[strlen(s._ptr) + 1];//另外開闢空間
            strcpy(_ptr, s._ptr);
        }
        return *this;
    }
    ~String()
    {
        if (_ptr)
        {
            delete[] _ptr;
        }
    }
private:
    char* _ptr;
};

再次執行下面程式碼:

String s1("sulijuan");
String s2(s1);
String s3;
s3 = s1;

除錯後可知各自開闢了一塊空間:

這裡寫圖片描述

模擬庫內string類的一些字串基本操作實現如下:

#define EXPLAND_CAPICITY 5
class String
{
public:
    String()                       //無參建構函式
        :_size(0)
        , _capicity(EXPLAND_CAPICITY)
        , _str(new char[EXPLAND_CAPICITY])
    {
        *_str = '\0';
    }
    String(char* str)               //建構函式過載
        :_size(strlen(str))           //根據宣告先後順序進行初始化
        , _capicity(_size+1)
        , _str(new char[_capicity])
    {
        strcpy(_str,str);
    }
    String(const String& s)         //深拷貝函式
        :_size(s._size)
        , _capicity(s._capicity)
        , _str(new char[strlen(s._str)+1])
    {
        strcpy(_str,s._str);
    }
    ~String()                      //解構函式 
    {
        if (_str)
        {
            delete[] _str;   
        }
    }
    String& operator=(const String& s)       //賦值運算子過載
    {
        if (this != &s)
        {
            delete[] _str;
            _str = new char[strlen(s._str)+1];
            strcpy(_str,s._str);
            _size = s._size;
            _capicity = s._capicity;
        }
        return *this;
    }
    void _CheckCapicity(int sCapicity)
    {
        if (_capicity - (_size + 1) < sCapicity)//檢查當前容量是否足以容下將要插入字串的長度
        {
            char* tmp = new char[_capicity + sCapicity];
            _capicity += sCapicity;
            strcpy(tmp, _str);       //_size沒變
            delete[] _str;           //將原來空間釋放掉
            _str = tmp;              //_str指向新開闢的空間
        }
    }
    void PushBack(char str)//尾插一個字元
    {
        _CheckCapicity(EXPLAND_CAPICITY);//如果當前所剩餘的容量小於5,則每次增加容量5,否則不增加
        _str[_size++] = str;    //將本來的'\0'改掉了
        _str[_size] = '\0';     //新的結尾
    }
    void PushBack(char* str)//尾插字串
    {
        assert(str);
        char* ptr = str;
        int strLen = strlen(str);
        _CheckCapicity(strLen);
        while (strLen--)
        {
            _str[_size++] = *ptr++;
        }
        _str[_size] = '\0';
    }
    void PopBack()       //尾刪字元
    {
        if (_size > 0)
        {
            _str[--_size] = '\0';
        }
    }
    void Insert(int index,char str)        //在下標為index處插入一個字元
    {
        assert(index < _size);
        _CheckCapicity(EXPLAND_CAPICITY);
        int i = _size;
        for (; i>=index; --i)
        {
            _str[i+1] = _str[i];
        }
        _str[index] = str;
        _size++;
    }
    void Insert(int index,char* str)      ////在下標為index後面插入字串
    {
        assert(index < _size);
        int strLen = strlen(str);
        _CheckCapicity(strLen);
        int i = _size;
        for (; i > index; i--)           
        {
            _str[i + strLen] = _str[i];      //把一個字元一次性挪到位
        }
        int j = index+1;
        char* ptr = str;
        while (strLen--)
        {
            _str[j++] = *ptr++;           //迴圈一個一個插入字元
            _size++;
        }
    }
    int Find(char str)//查詢一個字元
    {
        int i = 0;
        for (; i < _size; i++)
        {
            if (_str[i] == str)
            {
                return i;
            }
        }
        return -1;
    }
    int Find(char* str)//查詢字串
    {
        assert(str);
        int len = strlen(str);
        int i, j, k;
        for (i = 0; i < _size; i++)
        {
            k = i;
            for (j = 0; j < len; j++,k++)
            {
                if (_str[k] != str[j])
                {
                    break;
                }
            }
            if (str[j] == '\0')
            {
                return i;
            }
        }
        return -1;
    }
    /////////關係運算符過載函式////////////
    bool operator== (const String& s)
    {
        char* ptr1 = _str;
        char* ptr2 = s._str;
        while (*ptr1 == *ptr2)
        {
            if (*ptr1 == '\0')
            {
                return true;
            }
            ptr1++;
            ptr2++;
        }
        return false;
    }
    bool operator!= (const String& s)
    {
        return !(*this == s);
    }
    bool operator> (const String& s)
    {
        char* ptr1 = _str;
        char* ptr2 = s._str;
        while (*ptr1 == *ptr2)
        {
            if (*ptr1 == '\0')
            {
                return false;
            }
            ptr1++;
            ptr2++;
        }
        if (*ptr1 > *ptr2)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    bool operator>= (const String& s)
    {
        return (*this > s) || (*this == s);
    }
    bool operator< (const String& s)
    {
        return !(*this >= s);
    }
    bool operator<= (const String& s)
    {
        return !(*this > s);
    }
    //////////////////算術運算子過載函式////////////////
    String operator+ (const String& s)
    {
        String tmp(*this);
        tmp.PushBack(s._str);
        return tmp;
    }
    String& operator += (const String& s)
    {
        *this = *this + s;
        return *this;
    }
    friend ostream& operator<< (ostream& os, const String& s);//輸出<<運算子過載
private:
    int _size;          //字元個數
    int _capicity;      //字串容量
    char* _str;            //指向字串
};
ostream& operator<< (ostream& os,const String& s)
{
    os << s._str<<endl;
    return os;
}