string类的写时拷贝

莫水千流 莫水千流     2022-08-24     791

关键词:

由于浅拷贝使多个对象共用一块内存地址,调用析构函数时导致一块内存被多次释放,导致程序奔溃。

实现string类的时候通常显示的定义拷贝构造函数和运算符重载函数。

 

由于释放内存空间,开辟内存空间时花费时间,因此,在我们在不需要写,只是读的时候就可以不用新开辟内存空间,就用浅拷贝的方式创建对象,当我们需要写的时候才去新开辟内存空间。这种方法就是写时拷贝。 

技术分享

在构造函数中开辟新的空间时多开辟4个字节的空间,用来存放引用计数器,记录这快空间的引用次数。

  1. #include<iostream>  
  2. #include<stdlib.h>  
  3. using namespace std;  
  4. class String  
  5. {  
  6. public:  
  7.      String(char *str = "")  
  8.       :_str(new char[strlen(str) + 5])  
  9.      {  
  10.           *(int *)_str = 1;  
  11.           _str += 4;  
  12.           strcpy(_str, str);  
  13.      }  
  14.      ~String()  
  15.      {  
  16.           if (_str != NULL)  
  17.           {  
  18.               _Release();  
  19.           }  
  20.      }  
  21.      String(const String& str)  
  22.      {  
  23.           _str = str._str;  
  24.           ++_GetRefCount();  
  25.      }  
  26.      String& operator=(const String& str)  
  27.      {  
  28.           if (this != &str)  
  29.           {  
  30.                _Release();  
  31.                _str = str._str;  
  32.                ++ _GetRefCount();  
  33.           }  
  34.           return *this;  
  35.      }  
  36.      char& operator[](int index)//写时拷贝  
  37.      {  
  38.    
  39.           if (_GetRefCount()>1)//当引用次数大于1时新开辟内存空间  
  40.           {  
  41.                --_GetRefCount();//原来得空间引用计数器减1  
  42.                char *str = new char[strlen(_str) + 5];  
  43.                strcpy(str+4, _str);  
  44.                _str = str+4;  
  45.                _GetRefCount()++;  
  46.           }  
  47.           return _str[index];  
  48.      }  
  49.      friend ostream& operator<<(ostream& output, const String& str)  
  50.      {  
  51.           output << str._str;  
  52.           return output;  
  53.      }  
  54.    
  55. private:  
  56.      int& _GetRefCount()  
  57.      {  
  58.           return *(int *)(_str - 4);  
  59.      }  
  60.      void _Release()  
  61.      {  
  62.           if (--_GetRefCount() == 0)  
  63.           {  
  64.                delete[] (_str-4);  
  65.           }  
  66.      }  
  67. private:  
  68.      char *_str;  
  69. }; 

 

 

==============》

 

将_pCount与_str所指向的空间放在一起,即只用new开辟一次空间

技术分享

 

class String
{
	friend ostream& operator<<(ostream& os,String& s);
public:
	String(const char*str = "")
		:_str(new char[strlen(str)+1+4])
	{
		*(int *)_str = 1;	//*_pCount = 1
		_str = _str+4;	//找到数据存放的位置
		strcpy(_str,str);
		GetCount() = 1;
	}
	String(const String& str)
		:_str(str._str)
	{
		++GetCount();
	}
	~String()
	{
		if(--GetCount() == 0)
		{
			delete[] (_str-4);
		}
	}
	String& operator=(const String& s)
	{
		if (this != &s)
		{
			if (--GetCount() == 0)
			{
				delete[] (_str-4);  
			}
			++GetCount();
			_str = s._str;
		}
		return *this;
	}
private:
	int& GetCount()		//获得_pCount
	{
		return *((int *)_str-1);
	}
private:
	char *_str;
};
ostream& operator<<(ostream& os,String& s)
{
	os<<s._str;
	return os;
}
void test1()
{
	String str1("abcde");
	String str2(str1);
	String str3;
	str3 = str2;
	cout<<str1<<endl;
	cout<<str2<<endl;
	cout<<str3<<endl;
}

string类的写时拷贝与引用计数(代码片段)

...数时导致一块内存被多次释放,导致程序奔溃。实现string类的时候通常显示的定义拷贝构造函数和运算符重载函数。由于释放内存空间,开辟内存空间时花费时间,因此,在我们在不需要写,只是读的时候就... 查看详情

string类的深浅拷贝,写时拷贝

string类的深浅拷贝,写时拷贝浅拷贝:多个指针指向同一块空间,多次析构同一块内存空间,系统会崩溃。(浅拷贝就是值拷贝)深拷贝:给指针开辟新的空间,把内容拷贝进去,每个指针都指向自己的内存空间,析构时不会内... 查看详情

string类的实现写时拷贝浅析

  由于释放内存空间,开辟内存空间时花费时间,因此,在我们在不需要写,只是读的时候就可以不用新开辟内存空间,就用浅拷贝的方式创建对象,当我们需要写的时候才去新开辟内存空间。这种方法就是写时拷贝。这... 查看详情

c++深浅拷贝写时拷贝(代码片段)

前言:本章以string类为例介绍浅拷贝与深拷贝,引用计数写时拷贝作为了解内容,string类的模拟实现参考C++string类的模拟实现。文章目录1.浅拷贝2.深拷贝3.引用计数+写时拷贝1.浅拷贝浅拷贝:对于有申请... 查看详情

c语言如何获得变量的物理地址以及简单的写时拷贝测试

基本的思路:linux下的/proc/self是对自身进程映射的文件夹,里面的pagemap允许查看到每个虚拟页映射到的物理页。#include<stdio.h>#include<unistd.h>#include<inttypes.h>intptr_tMytop(uintptr_tvaddr)FILE*pagemap;intptr_ 查看详情

探秘写时拷贝的真相发布啦!

...们对写时拷贝并不陌生,Linuxfork和STLstring是比较典型的写时拷贝应用,本文只讨论 查看详情

深拷贝&浅拷贝&引用计数&写时拷贝

(1).浅拷贝:classString{public:String(constchar*str=""):_str(newchar[strlen(str)+1]){strcpy(_str,str);}~String(){if(NULL!=_str){delete[]_str;_str=NULL;}}private:char*_str;};intmain(){Strings1("hello");Str 查看详情

c++——浅拷贝深拷贝写时拷贝详解(代码片段)

...决浅拷贝的问题——引用计数写时拷贝浅拷贝与深拷贝用String类模拟用将“/0”拷贝进去:调用系统默认的拷贝构造函数,结果就是内容相同,地址相同。说明这个方法是浅拷贝方法。浅拷贝方法带来的问题就是同一... 查看详情

c++从青铜到王者第八篇:stl之string类的模拟实现(代码片段)

系列文章目录文章目录系列文章目录前言一、string类的模拟实现1.经典的string类问题2.浅拷贝3.深拷贝4.传统版的string类5.现代版的string类6.写时拷贝(了解)7.string类的模拟实现总结前言一、string类的模拟实现1.经典的string类问题上篇... 查看详情

写时拷贝(copyonwrite)(代码片段)

    适用于深拷贝提高效率的一种方法。    例如string类,在拷贝构造时,会要用到深拷贝。如果用浅拷贝,会导致两对象的指针指向同一块空间,导致对象析构时,导致同一块空间释放两次,程序奔... 查看详情

带有 APFS 的 macOS:终端中的写时复制

】带有APFS的macOS:终端中的写时复制【英文标题】:macOSwithAPFS:Copy-On-WriteinTerminal【发布时间】:2020-04-1205:34:02【问题描述】:我正在编写一些将备份数据组合到一个目录中的小脚本。然后将目录内容上传到云服务,然后我们可... 查看详情

c++初阶string底层框架模拟实现(代码片段)

...贝优缺点1.浅拷贝2.深拷贝3.深拷贝现代版4.写时拷贝三、string框架搭建1.框架定义2.构造函数3.析构函数4.赋值重载5.实现扩容6.增添数据7.删除数据8.数据查找9.iterator迭代器10.插入/提取流与getline函数四.完整代码一、前言本节文章... 查看详情

c++初阶string底层框架模拟实现(代码片段)

...贝优缺点1.浅拷贝2.深拷贝3.深拷贝现代版4.写时拷贝三、string框架搭建1.框架定义2.构造函数3.析构函数4.赋值重载5.实现扩容6.增添数据7.删除数据8.数据查找9.iterator迭代器10.插入/提取流与getline函数四.完整代码一、前言本节文章... 查看详情

Swift 如何实现 Array 的写时复制行为?

】Swift如何实现Array的写时复制行为?【英文标题】:HowSwiftimplementArray\'scopy-on-writebehavior?【发布时间】:2016-04-0803:27:18【问题描述】:看完buildbetterappswithvaluetype。在他们制作的Photoshop示例中,他们说在该图表的两个实例中唯一... 查看详情

fork()的写时复制技术(转载)

本文转载自http://www.cnblogs.com/wuchanming/p/4495479.html,为了方便以后查看。。。写时复制技术最初产生于Unix系统,用于实现一种傻瓜式的进程创建:当发出fork(  )系统调用时,内核原样复制父进程的整个地址空间并把复制的... 查看详情

写时拷贝技术

CopyOnWrite(COW):写时拷贝技术一、什么是写时拷贝技术:写时拷贝技术可以理解为“写的时候才去分配空间”,这实际上是一种拖延战术。举个栗子:650)this.width=650;"src="http://img.blog.csdn.net/20160829170427832?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkb... 查看详情

再谈qvector与qbytearray——qt的写时复制(copyonwrite)技术(代码片段)

...和赋值方面的一点东西,今天接着从QVector展开谈谈Qt的写时复制技术。老实说,“隐式共享,引用计数,写时复制”也是老调重弹的话题了,不过也是QTL与ST 查看详情

手撕stlstring类(代码片段)

string类标准库中的string类string类string类的常用接口说明string类的模拟实现Memberfunctions构造函数析构函数拷贝构造(深拷贝)赋值重载(深赋值)CapacitysizecapacityreserveresizeclearModifierspush_backappendinsertoperator+=swape... 查看详情