引用计数写时拷贝

引用计数

    String s1("abcdef");
    String s2(s1);
    String s3(s1);
    String s4("hello");
    s1 = s4;

  除初始化对象以外,每个构造函数(拷贝构造除外)需建立一个引用计数,用来记录多少对象与正在创建对象共享一块内存空间,当有新的指针指向这块空间时,引用计数加1。当创建一个对象且此对象未与其他对象共用一块内存空间时,将引用计数初始化为1。

描述

  拷贝构造不分配新的引用计数,而是拷贝计数器,并递增计数器。

描述

  析构函数递减计数器,每次递减代表该共用空间的成员少一个,当计数器减到0时,释放该空间。

  赋值运算符重载时,递减左侧对象的计数器,递增右侧对象的计时器。若左侧对象计数器为0,则需销毁该对象。

描述

写时拷贝

  写时拷贝是在需要修改对象时才真正去开辟空间拷贝数据,如果只是读数据,则只需浅拷贝即可。

  写时拷贝是通过引用计数实现的,当有对象需要修改其指向空间的值时,则需要重新开辟空间,保证修改此对象的值不会影响其他对象的值,此时要将旧空间的引用计数减1,新空间的引用计数加1。

描述

  String类中的两种写时拷贝:

  • 引用计数单独开辟空间

描述

class String
{
public:
    String(char* str = "")
        :_str(new char[strlen(str) + 1])
        , _pCount(new size_t(1))
    {
        strcpy(_str, str);
    }
    // s2(s1) 
    String(const String& s)
        :_str(s._str)
        , _pCount(s._pCount)
    {
        (*_pCount)++;
    }
    //s2 = s1 
    String& operator=(const String& s)
    {
        if (this != &s)
        {
            if (--(*_pCount) == 0)
            {
                delete[] _str;
                delete _pCount;
            }
            _str = s._str;
            _pCount = s._pCount;
            (*_pCount)++;
        }
        return *this;
    }
    ~String()
    {
        if (--(*_pCount) == 0)
        {
            delete[] _str;
            delete _pCount;
        }
    }
    const char* c_str()
    {
        return _str;
    }
    //减引用计数、拷贝、创建新的引用计数
    void CopyOnWrite()
    {
        if ((*_pCount)-- > 1)
        {
            char* tmp = new char[strlen(_str) + 1];
            strcpy(tmp, _str);
            _str = tmp;
            _pCount = new size_t(1);
        }
    }

    //如果指向该空间的指针只有一个,直接进行修改
    //如果指向该空间的指针数大于一,则调用写时拷贝开辟空间
    char& operator[](size_t pos)
    {
        if (*_pCount > 1)
        {
            CopyOnWrite();
        }
        return _str[pos];
    }
private:
    char* _str;
    size_t* _pCount;
};
  • 多开辟4个字节用来存放引用计数

描述

class String
{
public:
    String(char* str = "")
        :_str(new char[strlen(str) + 4 + 1])
    {
        if (_str == NULL)
        {
            *(int*)_str = 1;
            *(_str + 4) = '\0';
        }
        else
        {
            *(int*)_str = 1;    //前四个字节存放引用计数
            _str += 4;
            strcpy(_str, str);
        }
    }
    int& GetCount()
    {
        return *((int*)(_str - 4));
    }
    // s2(s1) 
    String(const String& s)
        :_str(s._str)
    {
        ++GetCount();     //向前偏移四个字节到引用计数,将计数器加1
    }
    //s2 = s1 
    String& operator=(const String& s)
    {
        if (this != &s)
        {
            if (--GetCount() == 0)
            {
                delete[] (_str - 4);
                _str = NULL;
            }
            _str = s._str;    //指向新空间
            ++GetCount();    //将新空间的计数器加1
        }
        return *this;
    }
    ~String()
    {
        if (_str == NULL)
        {
            return;
        }
        else
        {
            if (--GetCount() == 0)
            {
                delete [] (_str - 4);
                _str = NULL;
            }
        }
    }
    const char* c_str()
    {
        return _str;
    }
    void CopyOnWrite()
    {
        if (GetCount()-- > 1)
        {
            char* tmp = new char[strlen(_str) + 4 + 1];
            tmp += 4;
            strcpy(tmp, _str);
            _str = tmp;
            GetCount() = 1;
        }
    }
    char& operator[](size_t pos)
    {
        if (GetCount() > 1)
        {
            CopyOnWrite();
        }
        return _str[pos];
    }
private:
    char* _str; // 引用计数在头上 
};

描述

猜你喜欢

转载自blog.csdn.net/adorable_/article/details/80001021
今日推荐