zoukankan      html  css  js  c++  java
  • 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]='';
    			}
    			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
    ",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
    
  • 相关阅读:
    Dat2Rin.exe + runpkr00.exe 将*.T0* 数据转换成Rinex文件
    使用scipy.spatial.Delaunay 三角网的构建
    tinkphp3第三方类库引入问题
    git 撤销更改
    nginx各种配置
    elastic教程
    centos添加动态库默认搜索路径
    JSwebsocket问题:One or more reserved bits are on: reserved1 = 1, reserved2 = 1, reserved3 = 0
    关于脚本手动正常运行,放入crontab无效的问题
    mysql相关操作
  • 原文地址:https://www.cnblogs.com/oloroso/p/4594868.html
Copyright © 2011-2022 走看看