String封装——读时共享,写时复制
碰到过一位一直怀疑C++标准库(STL)效率的人,他说STL效率太低,企业开发根本不会用。我是持反对意见的。
说这话的人,肯定没有做过大量的调查。没有调查就没有发言权。
STL的效率是不低的,足够满足现在的绝大部分需求了。特别是当前的操作系统和硬件都以页为内存的基本管理单位,并且32位的系统(嵌入式还挺多的,但是嵌入式对内存的需求很大的比较少吧)的已经不是很多了。内存碎片的问题也就并不明显了。
前面说的与这里要说的是无关的,这里指向说一说String封装中的读共享,写复制。
学习过linux/unix系统编程的人,应该对读共享,写复制这个概念有一个比较清晰的了解,这个可见APUE的进程相关的章节。
实现原理
这个实现原理其实很简单,如果学习了shared_ptr智能指针,那应该是可以猜得到的。
其实关键的地方就是引用计数了。如果在string对象拷贝构造或者赋值(用已有对象)的时候,不进行拷贝,而只是进行引用计数的增加,数据采用共享方式。而在需要进行写操作的时候,才进行真正的拷贝操作。
代码实现
这里只是一个简单的实现,来说明这个原理,并没有多少实用价值。并且没有做到多线程安全。现在一般的也不会采取这种做法,因为现在内存都比较富裕了,还要解决多线程安全问题。VC6还是采用的COW技术,现在编译器自带的STL基本都不在采用,而改用(忘记名字了,原理就是内部使用一个数组,只有创建的字符串长度超过这个数组的时候,才进行内存分配)。
#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
String封装——读时共享,写时复制的更多相关文章
- php变量 写时改变 写时复制
写时复制 $var = 1; $var2 = $var; #此时$var2 与 $var 指向同一个zval refcount = 2: $var = 2; # 此时$val 改变 所以 $var 与 ...
- 线程不安全(Arraylist,HashSet,HashMap)和写时复制
package com.yangyuanyuan.juc1205; import java.util.List; import java.util.Map; import java.util.Set; ...
- Elasticsearch 读时分词、写时分词
初次接触 Elasticsearch 的同学经常会遇到分词相关的难题,比如如下这些场景: 为什么明明有包含搜索关键词的文档,但结果里面就没有相关文档呢?我存进去的文档到底被分成哪些词(term)了?我 ...
- 标准C++类std::string的内存共享和Copy-On-Write(写时拷贝)
标准C++类std::string的内存共享,值得体会: 详见大牛:https://www.douban.com/group/topic/19621165/ 顾名思义,内存共享,就是两个乃至更多的对象 ...
- c++ string写时复制
string写时复制:将字符串str1赋值给str2后,除非str1的内容已经被改变,否则str2和str1共享内存.当str1被修改之后,stl才为str2开辟内存空间,并初始化. #include ...
- 写时复制和fork,vfork,clone
写时复制 原理: 用了“引用计数”,会有一个变量用于保存引用的数量.当第一个类构造时,string的构造函数会根据传入的参数从堆上分配内存,当有其它类需要这块内存时,这个计数为自动累加,当有类析构时, ...
- String类的实现(4)写时拷贝浅析
由于释放内存空间,开辟内存空间时花费时间,因此,在我们在不需要写,只是读的时候就可以不用新开辟内存空间,就用浅拷贝的方式创建对象,当我们需要写的时候才去新开辟内存空间.这种方法就是写时拷贝.这也是一种 ...
- String 类的实现(2)引用计数与写时拷贝
1.引用计数 我们知道在C++中动态开辟空间时是用字符new和delete的.其中使用new test[N]方式开辟空间时实际上是开辟了(N*sizeof(test)+4)字节的空间.如图示其中保存N ...
- fork()和写时复制
写时复制技术最初产生于Unix系统,用于实现一种傻瓜式的进程创建:当发出fork( )系统调用时,内核原样复制父进程的整个地址空间并把复制的那一份分配给子进程.这种行为是非常耗时的,因为它需要: · ...
随机推荐
- Android学习笔记——Bundle
该工程的功能是实现不同线程之间数据的传递 以下代码是MainActivity.java中的代码 package com.example.bundle; import android.app.Activ ...
- Visual Studio 2012中Visual Assist破解办法
本工具有两种破解方式 1.破解方式一:Visual_Assist_X_DiE.exe 运行Visual_Assist_X_DiE.exe,勾选安装的VC版本,点击“Patch”按钮即可. 2.破解方式 ...
- css教程
网址:http://www.aa25.cn/layout/index.shtml
- PetaPoco 使用总结(一)
PetaPoco 使用总结(一) 前段时间,公司的一个项目希望用一个ORM 的框架,通过对比 Dapper 和 PetaPoco ,虽然Dapper 功能很强大,速度更快. 但是最终还是选择了比较简单 ...
- Haproxy安装配置及日志输出问题
简介: 软件负载均衡一般通过两种方式来实现:基于操作系统的软负载实现和基于第三方应用的软负载实现.LVS就是基于Linux操作系统实现的一种软负载,HAProxy就是开源的并且基于第三应用实现的软负载 ...
- mysql中set autocommit=0与start transaction区别
set autocommit=0,当前session禁用自动提交事物,自此句执行以后,每个SQL语句或者语句块所在的事务都需要显示"commit"才能提交事务. start tra ...
- SQL Server2008窗口计算
(一) 窗口的定义:指为用户指定的一组行,也称着"分区".如下图所示的窗口分区.每一个班级看作是一个数据窗口,一共有三个窗口 (二)窗口计算的相关方法 1)over()用法 格式 ...
- 【9-20】vimtutor学习笔记
第一节 ghjk移动光标 :q!:强制退出vim x:删除光标处的字符 i:在光标处插入 A:附加文本 :wq:保存文档并退出 第二节 dw:删除一个单词 d$:删除至行尾 de:删除光标处到该单词结 ...
- 【转载】Unity 优雅地管理资源,减少占用内存,优化游戏
转自:星辰的<Unity3D占用内存太大的解决方法> 最近网友通过网站搜索Unity3D在手机及其他平台下占用内存太大. 这里写下关于Unity3D对于内存的管理与优化. Unity3D ...
- CSS3的REM设置字体大小
在Web中使用什么单位来定义页面的字体大小,至今天为止都还在激烈的争论着,有人说PX做为单位好,有人说EM优点多,还有人在说百分比方便,以至于出现了CSS Font-Size: em vs. px v ...