【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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值