C++写时拷贝

写时拷贝copy on write

**首先什么时候会用到写时拷贝呢?
答:顾名思义修改的时候才拷贝,是为了解决浅拷贝的坑和平衡内存开销大而出的解决方案。

浅拷贝的坑——就是多个对象共用同一地址,在析构时同一块空间被释放多次,这种情况是不被允许的。

内存开销大——就是在每一次 深拷贝 时系统会新开辟空间,用来存放新对象。每创建一个新对象,就会开辟空间。每新开辟空间自然就会占内存,就会存在内存开销╮(╯_╰)╭。

深拷贝——就是为了“填浅拷贝的坑”,为新对象开辟新空间。

这里写图片描述

为了防止多次析构,但是还要考虑内存开销。我们想到用 引用计数(_refCount) 来起到一个内存使用的记录作用,让使用者清楚这块空间被who共用。在这块空间被析构时保证只有一个对象使用,即引用计数是1。当引用计数为0,这块空间真正被释放。

引用计数——即防止多个对象用一块空间时,这块空间被多次释放,用到的一个计数器。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
using namespace std;
namespace COW
{
    class String
    {
    public:
        String(const char* str)
            :_str(new char[strlen(str) + 1])
            , _refCount(new int(1))
        {
            strcpy(_str, str);
        }

        // s2(s1)
        String(String& s)
        {
            _str = s._str;
            _refCount = s._refCount;
            ++(*_refCount);
        }

        // s2 = s4
        String& operator=(const String& s)
        {
            if (_str != s._str)
            {
                Release();
                _str = s._str;
                _refCount = s._refCount;
                (*_refCount)++;
            }

            return *this;
        }

        void Release()
        {
            if (--(*_refCount) == 0)
            {
                cout << "delete" << endl;
                delete[] _str;
                delete _refCount;
            }
        }

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

            return _str[pos];
        }

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

        void CopyOnWrite()
        {
            if (*_refCount > 1)
            {
                char* tmp = new char[strlen(_str) + 1];
                strcpy(tmp, _str);
                --(*_refCount);
                _str = tmp;
                _refCount = new int(1);
            }
        }

        // Insert
        // Erase

        ~String()
        {
            Release();
        }

    private:
        char* _str;
        int* _refCount;
    };

这里测试时:

void TestString()
    {
        String s1("hello world");
        String s2(s1);
        String s3(s1);

        String s4("aaaaaaaaaaa");
        String s5(s4);

        s2 = s4;
    }

这里写图片描述

对于这个例子,我们还可以做一个优化,可以模仿new[]底层实现来开辟空间,让引用计数占用前四个字节的空间 。

这里写图片描述

优化代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
using namespace std;
namespace COW
{
    class String
    {
    private:
        char*_str;
    public:
        String(const char* str)
            :_str(new char[strlen(str) + 5])
        {
            //*((int*)_str) = 1;
            _str += 4;
            strcpy(_str, str);
            GetRefCount()=1;
        }
        int& GetRefCount()
        {
            return *((int*)(_str - 4));
        }
        ~String()
        {
            //if (--*((int*)_str - 4) == 0)
            if (--GetRefCount()==0)
            {
                cout << "delete" << endl;
                delete[](_str - 4);
            }
        }
        String(const String&s)
            :_str(s._str)
        {
            //(*(int*)(_str - 4))++;
            ++GetRefCount();
        }
        String& operator=(const String& s)
        {
            if (_str != s._str)
            {
                if (--GetRefCount() == 0)
                {
                    delete[](_str - 4);

                }
                _str = s._str;
                GetRefCount()++;
            }
            return *this;
        }
        const  char* GetStr()
        {
            return _str;
        }
    };
    void TestString()
    {
        String s1("hello");
        cout << s1.GetStr() << endl;
        String s2 = s1;
        cout << s2.GetStr() << endl;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值