写实拷贝

接前两篇深拷贝与浅拷贝,实现更加方便的写实拷贝
什么时候会写时才拷贝?很显然,当然是在共享同一块内存的类发生内容改变时,才会发生CopyOnWrite。比如string类的[]、=、+=、+、操作符赋值,还有一些string类中诸如insert、replace、append等成员函数,包括类的析构时。修改数据才会触发CopyOnWrite。

第一种

引用计数法:

思路:
定义一个int*_pcount,调用一次构造函数,++(*_pcount),调用一次析构函数,--(*_pcount),直至减为0,调用delete[] 释放对象,这种方法可以解决浅拷贝多次释放内存空间带来的内存泄漏问题。

代码实现:

//引用计数法
class String
{
public:
    //构造函数
    String(char *str)
        :_str(new char[strlen(str) + 1])
        , _pCount(new int(1))//初始化为1
    {
        strcpy(_str, str);
    }

    //拷贝构造函数
    //s2(s1)
    String(const String& s)
        : _str(s._str)
        , _pCount(s._pCount)
    {
        ++(*_pCount);

    }

    void Realse()
    {
        if (--(*_pCount)==0)//如果只有一个对象引用这块空间,则直接释放,否则计数器--
        {
            delete[] _str;
            delete[] _pCount;
            _pCount = NULL;
            _str = NULL;
        }
    }
    //赋值运算符重载
    //s2=s1
    String& operator=(const String& s)
    {
        if (_str != s._str)
        {
            Realse();
            _str = s._str;
            _pCount = s._pCount;
            ++(*_pCount);
        }
        return *this;
    }

    //析构函数
    ~String()
    {
        Realse();
    }

    void CopyOnWrite()//写实拷贝
    {
        if ((*_pCount) > 1)
        {
            char *newstr = new char[strlen(_str) + 1];//新建空间
            strcpy(newstr, _str);//直接拷贝
            --(*_pCount);

            _str = newstr;
            _pCount = new int(1);//此时_pCount指向不同空间
        }
    }
    //修改字符串中的字符
    char& operator[](size_t pos)
    {
        CopyOnWrite();
        return _str[pos];
    }
    const char* c_str()
    {
        return _str;
    }
private:
    char *_str;
    int* _pCount;//引用计数
};

void TestCopyOnWrite()
{
    String s1("1234");
    String s2 = s1;
    s1.operator[](2) = 's';
    cout << s1.c_str() << endl;
    cout << s2.c_str() << endl;
}

在监视窗口看:
这里写图片描述

结果为:
这里写图片描述

第二种

这里写图片描述
代码实现为:


class String
{
public:
    String(char *str )
        :_str(new char[strlen(str)+5])
    {
        _str += 4;//从第5个字节开始
        strcpy(_str, str);
        GetRfCount() = 1;//即相当于写法1的_pCount=1

    }

    //s2(s1)
    String(const String& s)
        :_str(s._str)
    {
        ++GetRfCount();
    }

    //s2=s1
    String& operator=(const String& s)
    {
        if (_str!=s._str)
        {
            if (--GetRfCount() == 0)
            {
                delete[](_str-4);
            }

            _str = s._str;
            ++GetRfCount();
        }
        return *this;
    }

    const char& operator[](size_t pos) const
    {
        return _str[pos];
    }

    void CopyOnWrite()
    {
        if (GetRfCount() > 1)
        {
            --GetRfCount();
            char *tmp = new char[strlen(_str) + 5];
            tmp += 4;//字符串从第五个字节开始存储

            strcpy(tmp, _str);
            _str = tmp;
            GetRfCount()=1;
        }
    }

    //获取前四字节值
    int& GetRfCount()
    {
        return *((int*)(_str - 4));
    }

    const char* c_str()
    {
        return _str;
    }

    char& operator[](size_t pos)
    {
        CopyOnWrite();
        return _str[pos];
    }

    ~String()
    {
        if (--GetRfCount() == 0)
        {
            delete[](_str - 4);
        }
    }
private:
    char *_str;
};

//测试部分
void Test4()
{
    String s1("1234");
    String s2(s1);
    String s3("world");
    //cout << s1.c_str() << endl;
    //cout << s1.GetRfCount() << endl;
    //cout << s2.c_str() << endl;
    //cout << s2.GetRfCount() << endl;


    s1 = s3;
    cout<<s1.GetRfCount()<<endl;
    cout<<s2.GetRfCount()<<endl;
    cout<<s3.GetRfCount()<<endl;

    s1.operator[](3) = 'w';
    cout << s1.c_str() << endl;
}

结果为:
这里写图片描述

最后这里推荐一篇陈皓的文章,详解写实拷贝

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值