引用计数写实拷贝

首先要了解的是计数写实拷贝是在浅拷贝的基础上进行的。
什么是浅拷贝?用一张图来解释
s2拷贝s1,不开辟新空间而是二者指向同一块空间,那么析构时会就会析构同一块空间两次,程序会出错
计数写实拷贝是通过设置计数器Pcount来解决:
Pcount的初始值为0,s1指向空间时Pcount+1,即Pcount=1,s2拷贝s1时,Pcount再+1,即Pcount=2;进行析构时,- -Pcount,当Pcount的值为0时再进行析构。这样解决了浅拷贝中重复析构同一空间的问题。
实现计数写实拷贝的方法有两种:
1.在为s1开辟空间时,同时开辟空间保存Pcount,代码为:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

class String
{
private:
    char* _str;
    int* _Pcount;
public:
    String(char* str = "")
        :_str(new char(strlen(str) + 1))
        , _Pcount(new int(1)){//为Pcount开辟空间
        strcpy(_str, str);
    }

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

    void Realease(){
        if (--(*_Pcount) = 0){
            delete[]_str;
            delete _Pcount;
        }
    }

    ~String(){
        Realease();
    }

    String& operator=(const String& s){
        if (_str != s._str){
            Realease();
            _str = s._str;
            _Pcount = s._Pcount;
            (*_Pcount++);
        }
        return *this;
    }

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

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

    const char* c_str(){
        return _str;
    }
};

void TestString()
{
    String s1("hello");
    String s2(s1);
    String s3("world");
    //s1[0] = 'x';

    cout<<s1.c_str()<<endl;
    cout<<s2.c_str()<<endl;
    cout<<s3.c_str()<<endl;

    s1 = s3;
    s2 = s3;
}
int main(){
    TestString();   
}

2.在s1开辟空间时,用它的前四个字节来保存Pcount,不用开辟另一块空间,代码如下:

class String
{
private:
    char* _str; // 引用计数在头上 
public:
    int& GetRefCount()
    {
        return *((int*)(_str - 4));
    }

    String(char* str ="")
        :_str(new char(strlen(str) + 5)){
        _str += 4;
        strcpy(_str, str);
        GetRefCount() = 1;
    }

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

   ~String(){
        if (--GetRefCount() == 0){//为0时析构
            delete[](_str - 4);
        }
    }

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

    const char* c_str(){
        return _str;
    }

    void CopyOnWrite(){
        if (GetRefCount() > 1){
            --GetRefCount();
            char* tmp = new char(strlen(_str) + 5);
            tmp += 4;
            strcpy(tmp, _str);
            _str = tmp;
            GetRefCount() = 1;
        }
    }

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

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

    cout << s1.GetRefCount() << endl;
    cout << s2.GetRefCount() << endl;
    cout << s3.GetRefCount() << endl;

    //s1 = s3;
    //cout<<s1.GetRefCount()<<endl;
    //cout<<s2.GetRefCount()<<endl;
    //cout<<s3.GetRefCount()<<endl;

    cout << s1[0] << endl;

    cout << s1.GetRefCount() << endl;
    cout << s2.GetRefCount() << endl;
    cout << s3.GetRefCount() << endl;
}
int main(){
TestString2();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值