String封装——读时共享,写时复制

Easter79
• 阅读 657

#String封装——读时共享,写时复制

本文由乌合之众瞎写http://my.oschina.net/oloroso

碰到过一位一直怀疑C++标准库(STL)效率的人,他说STL效率太低,企业开发根本不会用。我是持反对意见的。 说这话的人,肯定没有做过大量的调查。没有调查就没有发言权。 STL的效率是不低的,特别是当前的操作系统和硬件都以页为内存的基本管理单位,内存碎片的问题并不明显了。

前面说的与这里要说的是无关的,这里指向说一说String封装中的读共享,写复制。

学习过linux/unix系统编程的人,应该对读共享,写复制这个概念有一个比较清晰的了解,这个可见APUE的进程相关的章节。

##实现原理

这个实线原理其实很简单,如果学习了shared_ptr智能指针,那应该是可以猜得到的。

其实关键的地方就是引用计数了。如果在string对象拷贝构造或者赋值(用已有对象)的时候,不进行拷贝,而只是进行引用计数的增加,数据采用共享方式。而在需要进行写操作的时候,才进行真正的拷贝操作。

##代码实现

这里只是一个简单的实现,来说明这个原理,并没有多少实用价值。

#include <stdio.h>
#include <string.h>

struct shared_ptr{
    char*    data;    //数据
    int        ref;    //引用计数
};

class String{
    public:
        String(const char* str=NULL):iswrite(false)
        {
            p = new shared_ptr;
            if( str != NULL){
                p->data = new char[strlen(str)+1];
                strcpy(p->data,str);
            }
            else{
                p->data = new char[1];
                p->data[0]='\0';
            }
            p->ref = 1;
        }
        String(const String& s):iswrite(false)
        {
            p = s.p;
            p->ref += 1;
        }
        ~String()
        {
            if(p->ref == 1){
                delete p->data;
                delete p;
            }
            else{
                p->ref -=1;
            }
        }

        String& erase(int first,int last)
        {
            if(first < 0 ||last > strlen(p->data))return *this;

            if(!iswrite){    //如果不是可写状态
                shared_ptr* t=p;
                p = new shared_ptr;    //拷贝数据
                p->data = new char[strlen(t->data)+1];
                strcpy(p->data,t->data);
                p->ref = 1;
                t->ref -=1;    //原指向结构体引用计数减一
            }
            //擦除操作
            int len = strlen(p->data);
            for(int i = 0;i<len-last+1;++i){
                p->data[first + i] = p->data[last + i];
            }
            return *this;
        }
        void show() const
        {
            printf("ref = %d,data:%s\n",p->ref,p->data);
        }
    private:
        shared_ptr* p;    //数据
        bool        iswrite;//可写?
};

int main()
{

    String s1("hello world");
    String s2(s1);
    String s3(s2);
    s1.show();
    s2.show();
    s3.show();

    s2.erase(5,10);
    s1.show();
    s2.show();
    s3.show();
    return 0;
}

##运行结果

ref = 3,data:hello world
ref = 3,data:hello world
ref = 3,data:hello world
ref = 2,data:hello world
ref = 1,data:hellod
ref = 2,data:hello world
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
3年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Easter79 Easter79
3年前
SpringCloud 启动时报No active profile set, falling back to default profiles default
这在Spring程序启动时没有找到默认的配置文件所引发的错误,默认文件application.yml如下图: !这里写图片描述(https://oscimg.oschina.net/oscnet/4a822ce35ff8ed227a2c57f496787d95e5a.png)一般在项目中都会有多个,如有正式环境、测试环境等。如下
Stella981 Stella981
3年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Stella981 Stella981
3年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Stella981 Stella981
3年前
Apache加入到linux系统service
将Apache加入到linux系统service将apache加入到linux系统服务,用service命令来控制apache的启动和停止。本文由乌合之众瞎写http://my.oschina.com/oloroso(http://my.oschina.com/oloroso)1.生成Apache服务控制脚本1.1提取/usr/l
Wesley13 Wesley13
3年前
35岁是技术人的天花板吗?
35岁是技术人的天花板吗?我非常不认同“35岁现象”,人类没有那么脆弱,人类的智力不会说是35岁之后就停止发展,更不是说35岁之后就没有机会了。马云35岁还在教书,任正非35岁还在工厂上班。为什么技术人员到35岁就应该退役了呢?所以35岁根本就不是一个问题,我今年已经37岁了,我发现我才刚刚找到自己的节奏,刚刚上路。
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k