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

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

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

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

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

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

##实现原理

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

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

##代码实现

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

1#include <stdio.h> 2#include <string.h> 3 4struct shared_ptr{ 5 char* data; //数据 6 int ref; //引用计数 7}; 8 9class String{ 10 public: 11 String(const char* str=NULL):iswrite(false) 12 { 13 p = new shared_ptr; 14 if( str != NULL){ 15 p->data = new char[strlen(str)+1]; 16 strcpy(p->data,str); 17 } 18 else{ 19 p->data = new char[1]; 20 p->data[0]='\0'; 21 } 22 p->ref = 1; 23 } 24 String(const String& s):iswrite(false) 25 { 26 p = s.p; 27 p->ref += 1; 28 } 29 ~String() 30 { 31 if(p->ref == 1){ 32 delete p->data; 33 delete p; 34 } 35 else{ 36 p->ref -=1; 37 } 38 } 39 40 String& erase(int first,int last) 41 { 42 if(first < 0 ||last > strlen(p->data))return *this; 43 44 if(!iswrite){ //如果不是可写状态 45 shared_ptr* t=p; 46 p = new shared_ptr; //拷贝数据 47 p->data = new char[strlen(t->data)+1]; 48 strcpy(p->data,t->data); 49 p->ref = 1; 50 t->ref -=1; //原指向结构体引用计数减一 51 } 52 //擦除操作 53 int len = strlen(p->data); 54 for(int i = 0;i<len-last+1;++i){ 55 p->data[first + i] = p->data[last + i]; 56 } 57 return *this; 58 } 59 void show() const 60 { 61 printf("ref = %d,data:%s\n",p->ref,p->data); 62 } 63 private: 64 shared_ptr* p; //数据 65 bool iswrite;//可写? 66}; 67 68int main() 69{ 70 71 String s1("hello world"); 72 String s2(s1); 73 String s3(s2); 74 s1.show(); 75 s2.show(); 76 s3.show(); 77 78 s2.erase(5,10); 79 s1.show(); 80 s2.show(); 81 s3.show(); 82 return 0; 83}

##运行结果

1ref = 3,data:hello world 2ref = 3,data:hello world 3ref = 3,data:hello world 4ref = 2,data:hello world 5ref = 1,data:hellod 6ref = 2,data:hello world
点赞
收藏

评论区

加载中...

相关推荐

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

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

一篇文章带你了解JavaScript日期

日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用

Android So动态加载 优雅实现与原理分析

背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我