C++中的深浅拷贝和写时拷贝

浅拷贝

先来看一段代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;
class String
{
public:
    //构造函数
    String(const char *_pstr = "")
        :m_iSize(strlen(_pstr)+1)
    {
        m_pstr = new char[m_iSize];
        m_pstr[m_iSize] = '\0';
    }
    //拷贝构造函数
    String(const String& _string)
        :m_iSize(_string.m_iSize)
    {
        if (this != &_string)
        {
            m_pstr = _string.m_pstr;
        }
    }

    ~String()
    {
        if (NULL != m_pstr)
        {
            delete[] m_pstr;
            m_pstr = NULL;
        }
    }

private:
    char* m_pstr;
    int m_iSize;
};

void Funtest()
{
    String s1("hello world");
    String s2(s1);
}

int main()
{
    Funtest();
    return 0;
}

String s1(“hello world”);
调用String类的构造函数,将形参的内容拷贝到m_pstr中。
String s2(s1);
调用String类的拷贝构造函数,让m_pstr指向形参m_pstr空间。
接着函数向下执行,先析构s2,将s2.m_pstr所指向的空间释放,接下来释放s1,s1一直指向所申请空间,m_pstr已经为空,又去调析构函数去释放,程序崩溃。
这里写图片描述
注意:
当类里面有只针对象的时候,拷贝构造和赋值运算符重载值进行值拷贝(浅拷贝),两个对象同时指向同一块内存,对象销毁时该空间被释放了2次,程序崩溃。

深拷贝

简单的来说,【浅拷贝】是增加了一个指针,指向原来已经存在的内存。而【深拷贝】是增加了一个指针,并新开辟了一块空间,让指针指向这块新开辟的空间。
这里写了3个版本
1.普通版2.简洁版3.引用计数

//深拷贝---普通版 
class String
{
    friend ostream& operator<<(ostream& _cout, String& s);
public:
    String(const char* pStr = "")
    {
        if (NULL == pStr)
        {
            char* pTemp = new char[1];
            _pStr = pTemp;
            *_pStr = '\0';
        }
        else
        {
            char* pTemp = new char[strlen(pStr) + 1];
            _pStr = pTemp;
            strcpy(_pStr, pStr);
        }
    }

    ~String()
    {
        if (NULL != _pStr)
        {
            delete[] _pStr;
            _pStr = NULL;
        }
    }

    String(const String& s)
    {
        char* pTemp = new char[strlen(s._pStr) + 1];
        strcpy(pTemp, s._pStr);
        _pStr = pTemp;
    }

    String& operator=(const String& s)
    {
        if (this != &s)
        {
            char* pTemp = new char[strlen(s._pStr) + 1];
            strcpy(pTemp, s._pStr);
            _pStr = pTemp;
        }
        return *this;
    }
    String& operator+(const String& s)
    {
        char* _pCutStr = _pStr;
        char* _pSCurStr = s._pStr;
        char* Temp = new char[my_strlen(_pCutStr) + my_strlen(_pSCurStr) + 1];
        my_strcpy(Temp, _pCutStr);
        my_strcat(Temp, _pSCurStr);
        _pStr = Temp;
        return *this;
    }
    //String& operator+(const String& s, size_t pos, size_t n);
    bool operator>(const String& s)
    {
        if (this->Compare(s) > 0)
            return true;
        else
            return false;
    }
    bool operator<(const String& s)
    {
        if (this->Compare(s) < 0)
            return true;
        else
            return false;
    }
    bool operator==(const String& s)
    {
        if (this->Compare(s) == 0)
            return true;
        else
            return false;
    }
    String Copy(const String& s)
    {
        char* _pTstr = _pStr;
        char* sor = s._pStr;
        while (*_pTstr++ = *sor++)
        {
        }
        return *this;
    }
    String Copy(const String& s, size_t n)
    {
        char* _pTstr = _pStr;
        char* sor = s._pStr;
        while ((n--) && (*_pTstr++ = *sor++))
        {
        }
        return *this;
    }
    String StrStr(const String& s)
    {
        String cp;
        cp._pStr = (char *)_pStr;
        String s1, s2;

        if (!*s._pStr)
            return((char *)_pStr);

        while (*cp._pStr)
        {
            s1._pStr = cp._pStr;
            s2._pStr = (char *)s._pStr;

            while (*s1._pStr && *s2._pStr && !(*s1._pStr - *s2._pStr))
            {
                s1._pStr++; 
                s2._pStr++;
            }

            if (!*s2._pStr)
                return(cp._pStr);
            cp._pStr++;
        }

        return(NULL);
    }
private:
    int Compare(const String& s)
    {
        char* src = _pStr;
        char*dst = s._pStr;
        int ret = 0;
        while (!(ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
        {
            ++src;
            ++dst;
        }
        if (ret < 0)
            ret = -1;
        else if (ret > 0)
            ret = 1;

        return(ret);
    }
    int my_strlen(char* _pStr)
    {
        char* _pTstr = _pStr;
        int lenth = 0;
        while (*_pTstr++)
        {
            ++lenth;
        }
        return lenth;
    }

    char* my_strcpy(char* dec,const char* sor)
    {
        char* _pTstr = dec;
        while (*_pTstr++ = *sor++)
        {}
        return _pTstr;
    }

    char* my_strcat(char* dec, const char* sor)
    {
        char* _pTstr = dec;
        while (*_pTstr)
        {
            _pTstr++;
        }
        while (*_pTstr++ = *sor++)
        {
            ;
        }
        return _pTstr;
    }

private:
    char* _pStr;
};

ostream& operator<<(ostream& _cout, String& s)
{
    _cout << s._pStr;
    return _cout;
}

void FunTest()
{
    String str1 = "hello world";
    String str2 = "delete";
    bool ret = str1 > str2;
    String str3;
    cout << str1.StrStr(str2) << endl;
}

深拷贝——简洁版
class String
{
public:
    String(const char* pStr = "")
    {
        if (NULL == pStr)
        {
            char* pTemp = new char[1];
            _pStr = pTemp;
            *_pStr = '\0';
        }
        else
        {
            char* pTemp = new char[strlen(pStr) + 1];
            _pStr = pTemp;
            strcpy(_pStr, pStr);
        }
    }

    ~String()
    {
        if (NULL != _pStr)
        {
            delete[] _pStr;
            _pStr = NULL;
        }
    }

    String(const String& s)
    {
        String pTemp(s._pStr);
        _pStr = NULL;
        std::swap(_pStr, pTemp._pStr);  
    }

    String& operator=(const String& s)
    {
        if (this != &s)
        {
            String pTemp(s._pStr);
            std::swap(_pStr, pTemp._pStr);
        }
        return *this;
    }

private:
    char* _pStr;
};

void FunTest()
{
    String str1 = "hello";
    String str2 = str1;
    String str3="word";
    String str4=str3;
    str3 = str2;
}

浅拷贝优化-引用计数
class String
{
public:
    friend ostream& operator<<(ostream& _cout, String& s);
    String(const char* pStr = "")
    {
        if (NULL == pStr)
        {
            char* pTemp = new char[1];
            _pStr = pTemp;
            *_pStr = '\0';
        }
        else
        {
            char* pTemp = new char[strlen(pStr) + 1 + 4];
            *(int*)pTemp = 1;
            _pStr = (char*)((int*)pTemp + 1);
            strcpy(_pStr, pStr);
        }
    }

    ~String()
    {
        char* temp = (char*)((int*)_pStr - 1);
        if (--*(int*)temp == 0)
        {
            delete[] temp;
            _pStr = NULL;
        }
    }

    String(const String& s)
    {
        char* temp = (char*)((int*)s._pStr - 1);
        *(int*)temp += 1;
        _pStr = s._pStr;
    }

    String& operator=(const String& s)
    {
        if (this != &s)
        {
            char* temp = (char*)((int*)_pStr - 1);
            if (--*(int*)temp == 0)
            {
                delete[] temp;
                _pStr = NULL;
            }
            _pStr = s._pStr;
            *((int*)_pStr - 1) += 1;
        }
        return *this;
    }

private:
    char* _pStr;
};

ostream& operator<<(ostream& _cout, String& s)
{
    _cout << s._pStr;
    return _cout;
}


void FunTest()
{
    String s1;
    String s2 = "hello";
    String s3 ="word";
    /*String s4 = s3;*/
    s3 = s2;
    cout << s3 << endl;
    /*cout << s4 << endl;*/
}

int main()
{
    FunTest();
    system("pause");
    return 0;
}

写时拷贝

顾名思义,写时拷贝就是在需要修改这块空间的内容时才分配一块空间。同样用上边的例子,写时拷贝会存在一个计数器,并且多个对象指向同一块空间,每次创建一个新的对象时,计数器++,销毁时计数器 - -

写时拷贝
class String
{
public:
    friend ostream& operator<<(ostream& _cout, String& s);
    String(const char* str = "")
    {
        if (NULL == str)
        {
            char* pTemp = new char[1];
            *pTemp = '\0';
            _pStr = pTemp;
            int* pCTemp = new int(1);
            _pCount = pCTemp;
        }
        else
        {
            char* pTemp = new char[strlen(str) + 1];
            strcpy(pTemp, str);
            _pStr = pTemp;
            int* pCTemp = new int(1);
            _pCount = pCTemp;
        }
    }
    ~String()
    {
        if (--(*_pCount) == 0)
        {
            delete[] _pStr;
            _pStr = NULL;
            delete _pCount;
            _pCount = NULL;
        }
    }
    String(const String& str)
    {
        _pStr = str._pStr;
        _pCount = str._pCount;
        (*_pCount)++;
    }
    String& operator=(const String& str)
    {
        if (this != &str)
        {
            if (--(*_pCount) == 0)
            {
                delete[] _pStr;
                _pStr = NULL;
                delete _pCount;
                _pCount = NULL;
            }
            _pStr = str._pStr;
            _pCount = str._pCount;
            (*_pCount)++;
        }
        return *this;
    }
private:
    char* _pStr;
    int* _pCount;
};

ostream& operator<<(ostream& _cout, String& s)
{
    _cout << s._pStr;
    return _cout;
}


void FunTest()
{
    String s1 = "hello";
    cout << s1 << endl;
    String s2 = s1;
    cout << s2 << endl;
    String s3 = "word";
    s3 = s2;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值