String封装——读时共享,写时复制
2016-04-22 16:59
253 查看
碰到过一位一直怀疑C++标准库(STL)效率的人,他说STL效率太低,企业开发根本不会用。我是持反对意见的。
说这话的人,肯定没有做过大量的调查。没有调查就没有发言权。
STL的效率是不低的,足够满足现在的绝大部分需求了。特别是当前的操作系统和硬件都以页为内存的基本管理单位,并且32位的系统(嵌入式还挺多的,但是嵌入式对内存的需求很大的比较少吧)的已经不是很多了。内存碎片的问题也就并不明显了。
前面说的与这里要说的是无关的,这里指向说一说String封装中的读共享,写复制。
学习过linux/unix系统编程的人,应该对读共享,写复制这个概念有一个比较清晰的了解,这个可见APUE的进程相关的章节。
其实关键的地方就是
说这话的人,肯定没有做过大量的调查。没有调查就没有发言权。
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 worldhttp://www.cnblogs.com/oloroso/p/4594868.html
相关文章推荐
- 操作系统
- iOS Storyboard创建APP 的国际化操作
- 显示软键盘ListView包含EditText失去焦点
- Centos7 nfs 共享 mount远程目录
- Activity之间跳转与传值
- 图片压缩
- 从电子请柬切入,顺利融资3000万美金,“低频”的婚庆市场应该怎么做?
- cocos2d-C++ 学习UI控件(一)之 Button|CheckButton
- [Ruby] ruby创建类方法 ,以及class_eval 、instance_eval的使用
- Python IDLE reload(sys)后无法正常执行命令的原因
- jQuery学习(五)
- 阶段冲刺1
- TCP与UDP区别小结
- 路径
- java中main函数解析(转载)
- Docker 5分钟入门
- 《一个操作系统的实现》mount错误解决办法(mount 您必须指定文件系统的类型
- 自定义UIButton图片和文字的frame
- # sed 查找匹配行
- 连接打印机服务器