C++ String写时复制COW原理

保证写时(修改,覆盖)进行深拷贝,复制进行浅拷贝,通过引用计数管理内存空间。

cow.h

#ifndef COW_H
#define COW_H

#include <iostream>
#include <cstddef>

using namespace std;


class PstrRefcnt;
class ProxyChar;

class Cow_String {
    friend class ProxyChar;

    friend istream &operator>>(istream &, Cow_String &);

    friend ostream &operator<<(ostream &, const Cow_String &);

public:
    Cow_String(const char *str = "");

    Cow_String(const Cow_String &);

    Cow_String &operator=(const char *);

    Cow_String &operator=(const Cow_String &);

    ProxyChar operator[](size_t);

    const char *get_pstr() const;

    size_t get_refCnt() const;

    size_t get_size() const;

    size_t get_capacity() const;

    ~Cow_String();

private:
    PstrRefcnt *_pprc;
};

class ProxyChar {
    friend istream &operator>>(istream &, ProxyChar &&);
    friend ostream &operator<<(ostream &, ProxyChar &&);
public:
    ProxyChar(Cow_String &, size_t);

    ProxyChar &operator=(char c);
    ProxyChar &operator=(const ProxyChar &);

    operator char() const;

private:
    Cow_String &_cowStr;
    size_t _index;
};

#endif

cow.cpp

#include "cow.h"
#include <cstring>

/*      class PstrRefcnt     */
class PstrRefcnt {
    friend ostream &operator<<(ostream &, const PstrRefcnt &);

public:
    PstrRefcnt(const char *);

    PstrRefcnt(const PstrRefcnt &);

    inline void increaseRefcnt();

    inline void decreaseRefcnt();

    inline void shouldDelete();

    inline char *get_pstr() const;

    inline size_t get_refCnt() const;

    inline size_t get_size() const;

    inline size_t get_capacity() const;

    ~PstrRefcnt();

private:
    size_t _refCnt;
    size_t _size;
    size_t _capacity;
    char *_pstr;
};

PstrRefcnt::PstrRefcnt(const char *str)
        : _size(strlen(str)), _capacity(_size + 1), _refCnt(0), _pstr(new char[_capacity]) {
    strcpy(_pstr, str);
    increaseRefcnt();
}

PstrRefcnt::PstrRefcnt(const PstrRefcnt &other)
        : _size(other._size), _capacity(_size + 1), _refCnt(0), _pstr(new char[_capacity]) {
    strcpy(_pstr, other._pstr);
    increaseRefcnt();
}

void PstrRefcnt::increaseRefcnt() {
    _refCnt++;
}

void PstrRefcnt::decreaseRefcnt() {
    _refCnt--;
}

void PstrRefcnt::shouldDelete() {
    decreaseRefcnt();
    if (_refCnt == 0) {
        delete this;
    }
}

char *PstrRefcnt::get_pstr() const {
    return _pstr;
}

size_t PstrRefcnt::get_refCnt() const {
    return _refCnt;
}

size_t PstrRefcnt::get_size() const {
    return _size;
}

size_t PstrRefcnt::get_capacity() const {
    return _capacity;
}

PstrRefcnt::~PstrRefcnt() {
    if (_pstr) {
        cout << *this << " " << "~PstrRefcnt()" << endl;
        delete[] _pstr;
        _pstr = nullptr;
    }
}

ostream &operator<<(ostream &os, const PstrRefcnt &prc) {
    os << prc._pstr;
    return os;
}
/*      class PstrRefcnt     */

/*      class ProxyChar     */
ProxyChar::ProxyChar(Cow_String &cowStr, size_t index)
        : _cowStr(cowStr), _index(index) {
}

ProxyChar &ProxyChar::operator=(const char c) {
    if(_cowStr.get_pstr()[_index] != c && _cowStr.get_refCnt() > 1){
        _cowStr._pprc->shouldDelete();
        _cowStr._pprc = new PstrRefcnt(*_cowStr._pprc);
    }
    _cowStr._pprc->get_pstr()[_index] = c;
    return *this;
}

ProxyChar &ProxyChar::operator=(const ProxyChar &other) {
    *this = static_cast<char>(other);
    return *this;
}

ProxyChar::operator char() const {
    return _cowStr.get_pstr()[_index];
}

istream &operator>>(istream &is, ProxyChar &&prc) {
    char c;
    is >> c;
    prc = c;
    return is;
}

ostream &operator<<(ostream &os, ProxyChar &&prc) {
    os << prc._cowStr.get_pstr()[prc._index];
    return os;
}
/*      class ProxyChar     */


/*      class Cow_String     */
Cow_String::Cow_String(const char *str)
        : _pprc(new PstrRefcnt(str)) {
}

Cow_String::Cow_String(const Cow_String &other)
        : _pprc(other._pprc) {
    _pprc->increaseRefcnt();
}

Cow_String &Cow_String::operator=(const char *str) {
    if (strcmp(get_pstr(), str) != 0) {
        _pprc->shouldDelete();
        _pprc = new PstrRefcnt(str);
    }
    return *this;
}

Cow_String &Cow_String::operator=(const Cow_String &other) {
    if (this != &other) {
        _pprc->shouldDelete();
        _pprc = other._pprc;
        _pprc->increaseRefcnt();
    }
    return *this;
}

ProxyChar Cow_String::operator[](size_t index) {
    return ProxyChar{*this, index};
}

const char *Cow_String::get_pstr() const {
    return _pprc->get_pstr();
}

size_t Cow_String::get_refCnt() const {
    return _pprc->get_refCnt();
}

size_t Cow_String::get_capacity() const {
    return _pprc->get_capacity();
}

size_t Cow_String::get_size() const {
    return _pprc->get_size();
}

Cow_String::~Cow_String(){
    _pprc->shouldDelete();
}

istream &operator>>(istream &is, Cow_String &cowString) {
    char buffer[1024];
    is >> buffer;
    cowString._pprc->shouldDelete();
    cowString._pprc = new PstrRefcnt(buffer);
    return is;
}

ostream &operator<<(ostream &os, const Cow_String &cowString) {
    os << *cowString._pprc;
    return os;
}
/*      class Cow_String     */

main.cpp

#include "cow.h"

void test(){
    Cow_String s1 = "MikuMiku";
    Cow_String s2 = s1;
    Cow_String s3, s4;
    cout << "s1: " << s1; //预期输出MikuMiku
    cout << " s1.refcnt: " << s1.get_refCnt() << endl; //预期输出2

    s4 = s3 = s1; //这里析构两次
    cout << "s1: " << s1; //预期输出MikuMiku
    cout << " s1.refcnt: " << s1.get_refCnt() << endl; //预期输出4

    s1[1] = 'o';
    s2[2] = 'o';
    s3[3] = s2[2];
    cin >> s4[4]; //输入o
    cout << s4[s4.get_size()-1] << endl; //预期输出u
    cout << "s1: " << s1; //预期输出MokuMiku
    cout << " s1.refcnt: " << s1.get_refCnt() << endl; //预期输出1
    cout << "s2: " << s2; //预期输出MiouMiku
    cout << " s2.refcnt: " << s2.get_refCnt() << endl; //预期输出1
    cout << "s3: " << s3; //预期输出MikoMiku
    cout << " s3.refcnt: " << s3.get_refCnt() << endl; //预期输出1
    cout << "s4: " << s4; //预期输出Mikuoiku
    cout << " s4.refcnt: " << s4.get_refCnt() << endl; //预期输出1

    //结束析构四次
}

int main(){
    test();
    return 0;
}

 g++ main.cpp cow.cpp

./a.out

运行结果:

s1: MikuMiku s1.refcnt: 2
 ~PstrRefcnt()
 ~PstrRefcnt()
s1: MikuMiku s1.refcnt: 4
o
u
s1: MokuMiku s1.refcnt: 1
s2: MiouMiku s2.refcnt: 1
s3: MikoMiku s3.refcnt: 1
s4: Mikuoiku s4.refcnt: 1
Mikuoiku ~PstrRefcnt()
MikoMiku ~PstrRefcnt()
MiouMiku ~PstrRefcnt()
MokuMiku ~PstrRefcnt()

进程已结束,退出代码为 0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值