c++深浅拷贝&写时拷贝实现

来源:互联网 发布:淘宝网店人员配置 编辑:程序博客网 时间:2024/06/06 13:49

一:浅拷贝&深拷贝

浅拷贝:在拷贝构造的时候,直接将原内容的地址交给要拷贝的类,两个类共同指向一片空间。但是存在很大的缺陷:①一旦对s2进行操作,s1的内容也会改变;②析构时先析构s2,再析构s1,但是由于s1,s2指向同一片空间,会导致一片空间的二次析构导致出错。

深拷贝:通过开辟和源空间大小相同的空间并将内容拷贝下来再进行操作。不论是否对s2进行操作,都会拷贝一片相同大小的空间以及内容下来。

图示如下:

这里写图片描述

深拷贝实现如下:

#include <iostream>using namespace std;class String{public:    String(char* str = "")        :_str(new char[strlen(str)+1])    {        strcpy(_str, str);    }    //传统写法,开辟空间    String(const String& s)    {        _str = new(char[strlen(s._str) + 1]);        strcpy(_str, s._str);    }    //现代写法,利用构造函数    //String(const String& s)    //  :_str(NULL)    //{    //  String tmp(s._str);    //  swap(_str, tmp._str);    //}    //****************赋值运算符重载**************    //String& operator=(const String& s)    //{    //  if (this != &s)    //  {    //      delete[] _str;    //      _str = new char[strlen(s._str) + 1];    //      strcpy(_str, s._str);    //  }    //  return *this;    //}    //****************赋值运算符重载**************    String& operator=(String& s)    {        swap(_str, s._str);        return *this;    }    //***************析构函数********************    ~String()    {        if (_str)        {            delete[] _str;        }    }private:    char* _str;};

二:写时拷贝

写时拷贝:引入一个计数器,每片不同内容的空间上都再由一个计数器组成,在构造第一个类指向时,计数器初始化为1,之后每次有新的类也指向同一片空间时,计数器加价;在析构时判断该片空间对应计数器是否为1,为1则执行清理工作,大于1则计数器-1。如果有需要进行增删等操作时,再拷贝空间完成,有利于提高效率。

写法一:

#include <iostream>using namespace std;class String{public:    String(char* str = "")        :_str(new char[strlen(str)]+1)        , _refCount(new int(1))    {        strcpy(_str, str);    }    String(const String& str)        : _str(str._str)        ,_refCount(str._refCount)    {        (*_refCount)++;    }    ~String()    {        release();    }    String& operator= (const String& s)    {        if (_str != s._str)        {            release();            _refCount = s._refCount;            (*_refCount)++;            _str = s._str;        }        return *this;    }    void release()    {        if ((*--_refCount) == 0)        {            delete[] _str;            delete _refCount;        }    }private:    char* _str;    int* _refCount;};

缺点:每构造一个新类,就会多开四个字节,会导致空间中有许多的内存碎片。


第二种:

class String{public:    String(char* str = "")        :_str(new char[strlen(str)+1+4])    {        *(int*)_str = 1;        _str += 4;        strcpy(_str, str);    }    String(const String& s)        :_str(s._str)    {        ++GetCount();    }    ~String()    {        release();    }    String& operator=(const String& s)    {        if (this != &s)        {            realease();            _str = s._str;            GetCount()++;        }        return *this;    }    void release()    {        if (--GetCount() == 0)        {            _str -= 4;            delete[] _str;              }    }    int& GetCount()    {        return *((int*)_str - 1);    }private:    char* _str;};

注意:由于计数器存放在了_str首地址-4的地址上,所以在析构时一定要注意全部释放,避免内存泄漏。

图示如下:

这里写图片描述