首页 > 编程语言 >C++基础语法实现写时复制CowString

C++基础语法实现写时复制CowString

时间:2024-11-13 22:43:45浏览次数:3  
标签:pstr self CowString C++ char refCountLength ._ 写时

前言: 

CowString写时复制设计思路

难点:

通过下标访问字符串元素的基本思路重载[]运算符,在函数中直接返回该位置指针的解引用,但此时返回值为char类型,对于进行单个字符串修改的操作,如:str[1]='H';,无法处理赋值时的写时复制操作,只能通过输出流运算符输出char。

解决方法:

可以在CowString类内嵌套设置一个代理类,CowString的重载[]函数只需要返回该代理类CharProxy该代理类重载输出流运算符和赋值运算符,代理类进行后续操作的进行。

嵌套类权限:内部类相当于是定义在外部类中的外部类的友元类

#include <iostream>
#include <cstring>
using std::cout;
using std::endl;
using std::ostream;
class CowString
{
    class CharProxy // 代理
    {
    public:
        CharProxy(CowString &self, const size_t idx)
            : _self(self), _idx(idx)
        {
        }

        bool operator=(char ch);
        friend ostream &operator<<(ostream &os, const CharProxy &rhs);
        //CharProxy为私有内部类,该函数需要在内外部类中同时声明友元

    private:
        CowString &_self;
        size_t _idx;
    };

public:
    CowString();
    ~CowString();
    CowString(const CowString &rhs);
    CowString(const char *pstr);
    CowString &operator=(const CowString &rhs);

    CharProxy operator[](size_t idx);

    const char *c_str() { return _pstr; };
    size_t size() const { return strlen(_pstr); };
    int use_count() { return *(int *)(_pstr - refCountLength); };

    friend ostream &operator<<(ostream &os, const CowString &rhs);
    friend ostream &operator<<(ostream &os, const CharProxy &rhs);

private:
    char *_pstr;
    static const int refCountLength = 4;
};
// 构造
CowString::CowString()
    : _pstr(new char[refCountLength + 1]())
{
    *(int *)_pstr = 1;       // 引用计数置为1
    _pstr += refCountLength; // 后移至数据存放头
}
CowString::CowString(const CowString &rhs)
    : _pstr(rhs._pstr)
{
    ++*(int *)(_pstr - refCountLength);
}
CowString::CowString(const char *pstr)
    : _pstr(new char[refCountLength + 1 + strlen(pstr)])
{
    *(int *)_pstr = 1; // 引用计数置为1
    _pstr += refCountLength;
    strcpy(_pstr, pstr);
}
CowString &CowString::operator=(const CowString &rhs)
{
    if (&rhs != this) // 非自复制
    {
        --*(int *)(_pstr - refCountLength);
        if (*(int *)(_pstr - refCountLength) == 0)
        {
            delete[] (_pstr - refCountLength);
            _pstr = nullptr;
        }
        _pstr = rhs._pstr;
        ++*(int *)(_pstr - refCountLength);
    }
}

CowString::CharProxy CowString::operator[](size_t idx)
{
    return CharProxy(*this, idx);
}

// 析构
CowString::~CowString()
{
    --*(int *)(_pstr - refCountLength);
    if (*(int *)(_pstr - refCountLength) == 0)
    {
        delete[] (_pstr - refCountLength);
        _pstr = nullptr;
    }
}
ostream &operator<<(ostream &os, const CowString &rhs)
{
    os << rhs._pstr;
    return os;
}
// 代理类实现
bool CowString::CharProxy::operator=(char ch)
{
    if (_idx < _self.size())
    {
        if (_self.use_count() > 1)
        {
            // 深拷贝
            char *ptemp = new char[refCountLength + 1 + strlen(_self._pstr)]();
            ptemp += refCountLength;
            strcpy(ptemp, _self._pstr);

            // 原堆空间字符串引用计数减一
            --*(int *)(_self._pstr - refCountLength);
            if (*(int *)(_self._pstr - refCountLength) == 0)
            {
                delete[] (_self._pstr - refCountLength);
                _self._pstr = nullptr;
            }

            // 修改指向
            _self._pstr = ptemp;
            // 初始化引用计数
            *(int *)(_self._pstr - _self.refCountLength) = 1;
            // 写入字符
            *(_self._pstr + _idx) = ch;
            return true;
        }
    }
    else
    {
        cout << "out of range" << endl;
        return false;
    }
}
ostream &operator<<(ostream &os, const CowString::CharProxy &rhs)
{
    if (rhs._idx < rhs._self.size())
    {
        os << *(rhs._self._pstr + rhs._idx);
        return os;
    }
    else
    {
        cout << "out of range" << endl;
        return os;
    }
}

标签:pstr,self,CowString,C++,char,refCountLength,._,写时
From: https://blog.csdn.net/weixin_73809064/article/details/143753833

相关文章

  • C++单例模式实现
    单例模式(SingletonPattern)是软件设计模式中的一种,用于确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。一、初始版本(手动创建释放)一个类只有一个实例的实现方法:隐藏构造函数,是外界无法创造对象通过类静态成员函数getInstance返回静态局部对象指针(指向堆空间的......
  • C++ 左值引用和右值引用之间的转换
    intretVal(int&&v){cout<<"右值引用:";returnv;}intretVal(int&v){cout<<"左值引用:";returnv;}intretVal(constint&v){cout<<"const左值引用:";returnv;}i......
  • 【c++】广度优先搜索详解
    BFS(图论)BFS全称是 BreadthFirstSearch,中文名是宽度优先搜索,也叫广度优先搜索。是图上最基础、最重要的搜索算法之一。所谓宽度优先。就是每次都尝试访问同一层的节点。如果同一层都访问完了,再访问下一层。这样做的结果是,BFS算法找到的路径是从起点开始的 最短 合法......
  • 【c++】游戏作品分享
    1.法术对战#include<iostream>usingnamespacestd;intmain(){ intyhp=444; intchp=2000; intaaa; intlan=2000; intdu=0; inttuy=0; for(inti=1;i<=9999;i++) { cout<<"你的血量:"<<yhp<<endl<<"电脑血量:&quo......
  • 【c++】游戏作品分享
     c++代码#include<bits/stdc++.h>#include<xiaohoucode.h>#include<time.h>#include<stdlib.h>#include<unistd.h>#include<termio.h>#include<ctype.h>#include<stdio.h>#include<math.h>usingnamespa......
  • Visual C++ 6.0中文版安装包下载教程及win11安装教程
    本文分享的是VisualC++6.0(简称VC++6.0)中文版安装包下载及安装教程,关于win11系统下安装和使用VC++6.0使用问题解答,大家在安装使用的过程中会遇到不同的问题,如遇到解决不了的问题请给我留言!一、安装包的下载vc6.0安装包下载连接:https://pan.quark.cn/s/979dd8ba4f35二、......
  • C++零基础入门&趣味学信息学奥赛_开发环境安装
    Arduino软件安装,安装树莓派Pico开发板及上传Pico固件目录1.安装Windows驱动程序1.1.下载安装arduino软件:1.2.安装开发板Pico1.3.上传Arduino兼容的Pico固件1.安装Windows驱动程序                                        ......
  • C++ 移动构造和拷贝构造函数匹配
    既有拷贝构造又有移动构造这个比较好理解,普通的函数匹配规则就可以。右值移动,左值拷贝。——《C++Primer》P477我们不能隐式地将一个右值引用绑定到一个左值。有拷贝构造但没有移动构造这种情况,右值也会被拷贝。如果一个类没有移动构造函数,函数匹配规则保证该类型的对象......
  • C++继承和参数化类型(模板)各自的优点
    在C++中,继承和参数化类型(模板)都是强大的代码重用机制,它们各自具有独特的优点。以下是对这两种机制优点的比较和归纳:C++继承的优点代码重用:继承允许子类继承父类的属性和方法,从而避免了重复编写相同的代码。这不仅提高了开发效率,还减少了代码中的冗余。扩展性:通过继承,可以创建......
  • C++ 逆向之常用字符集互转
    在过往的编程过程中,常常会因为碰到字符集问题而头痛,而每次在进行字符集转换的时候,各种搜索网上文档,想找字符集转换的示例程序,但是都不尽人意,本篇文章的目的就是彻底解决之前编程过程中对字符集认识以及字符集转换之间似懂非懂、云里雾里的状态,并在文章结尾附上ANSI、UNICODE和U......