string类模拟之引用计数和写时拷贝

原创 2018年04月16日 13:17:40

在 string类的模拟之深浅拷贝  中,我们可以看到,程序浅拷贝导致的崩溃,是因为多次释放内存引起的多次析构,那么我们可以添加一个计数器,这里称之为引用计数,来表示当前的空间有多少指针指向它,如果大于一的话,那么在调析构函数的时候,就只对引用计数减一,当减到只剩一的时候就可以安心的释放内存空间了。

引用计数的本质就是一个整形变量,那么我们到底应该怎么给出引用计数的形式呢?

1.整形成员变量(不可以,每个对象都会单独存一份,就会导致计数器并不统一(数值只在相邻的对象发生传递),在析构的时候内存无法释放,导致内存泄漏)


2.静态成员变量 (不可以,静态成员变量为所有对象共享,任何对象都可以对它进行修改,每创建一个对象我们都对计数器加1,却忽略了创建的新对象是否与已存在的对象占同一块空间


3.指针变量(可以)

class String
{
public:
	String(const char* pStr = "")//构造函数  
		:_pCount(new int(0))
		, _pStr(new char[strlen(pStr) + 1])
	{
			strcpy(_pStr, pStr);
			*_pCount = 1;
	}
	String(const String& s) 
		:_pCount(s._pCount)
	{
		_pStr = (char*)s._pStr;
		_pCount = s._pCount;
		(*_pCount)++;
	}
	~String()//析构 
	{
		if (NULL != _pStr)
		{
			if (--(*_pCount) == 0)
			{
				delete[]_pCount;//释放计数器指针  !!!
				delete[]_pStr;
				_pStr = NULL;
				_pCount = NULL;
			}
		}
	}
	String& operator=(String& s)//赋值运算符重载  
	{
		if (_pStr != s._pStr)
		{
			_pStr = s._pStr;
			_pCount = s._pCount;
			(*_pCount)++;
		}
		return *this;
	}
private:
	int* _pCount;
	char* _pStr;
};


void Funtest()
{
	String s1("abcd");
	String s2(s1);
	String s3 = "1111";//调用拷贝构造函数(编译器会s2直接初始化s3)  
	String s4;//s4对象已经存在了  
	s4 = s3;//编译器会调用赋值运算符重载将s3的值赋给s4  
}

至此,好像已经解决了多次析构的问题,但是还不够好(开辟了两块较小的内存空间,造成内存的碎片化问题)。我们采取下面这样的方法来避免。


再说说每次拷贝都开辟内存空间,这样的做法虽然有效的避免了内存的多次释放的问题,但它带来的问题确是,需要不停的开辟内存,尽管可能只是读一下内存中的字符而已,这就造成的系统资源的浪费。由此,我们可以采用写时拷贝的方式来避免这样的问题。

只要S2的操作只是读取内存时,那么并不会开辟空间,而发生写(增删改)的操作时,我们就新开辟空间。改变S2的指向。


String.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "String.h"

int& String::GetRefCount()
{
	return *((int *)(_str - 4));
}


String::~String()
{
	if (--GetRefCount() == 0)
	{
		delete[](_str - 4);
	}
}

String::String(const String& s)
		:_str(s._str)
{
	GetRefCount()++;
}

String& String::operator=(const String& s)
{
	if (_str != s._str)	//自赋值
	{
		if (--GetRefCount() == 0)	//只有一个引用的时候
		{
			delete[](_str - 4);
		}

		_str = s._str;		//指向位置改变,引用计数增加
		GetRefCount()++;	
	}
	return *this;
}


const char* String::c_str()
{
	return _str;
}

void String::CopyOnWrte()
{
	if (GetRefCount() > 1)	//引用计数大于一	?  在使用的函数中判断减少压栈过程
	{
		GetRefCount()--;

		char* newstr = new char[strlen(_str) + 5];

		strcpy(newstr + 4, _str);
		_str = newstr + 4;
		GetRefCount() = 1;
	}
}

char& String::operator[](size_t pos)
{
	CopyOnWrte();
	return _str[pos];
}


void TestClass()
{
	String s1("hello world!");
	String s2(s1);
	String s3("this is czf");
	s1 = s3;
	String s4(s3);

	s3[3] = 'r';
}


int main()
{
	TestClass();
	return 0;
}
String.h
#pragma	once
#include <string.h>

#define NULL 0

class String
{
public:
	String(char * str = "")
		:_str(new char[strlen(str) + 5])
	{
		_str += 4;
		strcpy(_str, str);
		*((int *)(_str - 4)) = 1;
	}

	String(const String& s);
	String& operator=(const String& s); 
	~String();
	const char *c_str();
	void  CopyOnWrte();
	int& GetRefCount();
	char& operator[](size_t pos);

private:
	char *_str;
};



版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/bian_cheng_ru_men/article/details/79958917

string类写时拷贝的模拟实现

为了解决string类中浅拷贝的问题,在windows系统下它则以深拷贝来解决这一问题,由于深拷贝要不断的开辟内存空间,并花费时间,所以在linux/unix系统下则采用写时拷贝(Copy_On_Wr...
  • L_XRUI
  • L_XRUI
  • 2017-03-23 18:12:12
  • 565

由深拷贝与浅拷贝引发的引用计数、写时拷贝技术

一、理解深拷贝和浅拷贝: #include using namespace std; class String { public: String(const char *str = "") {...
  • wjxxaut
  • wjxxaut
  • 2016-08-13 21:14:58
  • 399

String类引用计数的写时拷贝

写时拷贝: 当一个对象被拷贝构造多次,在不改变内容的情况下,多个对象共用同一个空间。 如果某个对象要改变内容,就要另外开辟一块相同的空间,然后改变这个对象的_str指针,再进行写操作 #...
  • AlwenZwei
  • AlwenZwei
  • 2017-07-13 15:15:44
  • 148

string类的写时拷贝与引用计数

由于浅拷贝使多个对象共用一块内存地址,调用析构函数时导致一块内存被多次释放,导致程序奔溃。 实现string类的时候通常显示的定义拷贝构造函数和运算符重载函数。 由于释放内存空间,开辟内存空间时花...
  • yangle4695
  • yangle4695
  • 2016-08-31 11:19:56
  • 317

string类的写时拷贝

由于浅拷贝使多个对象共用一块内存地址,调用析构函数时导致一块内存被多次释放,导致程序奔溃。实现string类的时候通常显示的定义拷贝构造函数和运算符重载函数。 由于释放内存空间,开辟内存空间时花费时间...
  • xyzbaihaiping
  • xyzbaihaiping
  • 2016-04-11 20:04:29
  • 925

C++::浅拷贝,深拷贝,引用计数的拷贝,写时拷贝

【什么情况下会用到c++中的拷贝构造函数】:  1)用已经存在的同类的对象去构造出另一个新的对象   2)当函数的形参是类的对象时,这时调用此函数,使用的是值的拷贝,也会调用拷贝构造函数   3)当...
  • lalu58
  • lalu58
  • 2017-01-04 21:47:10
  • 1361

STL——STL中string的写时拷贝机制

STL中string的写时拷贝机制
  • Linux_ever
  • Linux_ever
  • 2016-03-25 20:53:27
  • 613

写时拷贝的方式实现C++中string类

写时拷贝的两种实现方式:计数器和引用计数
  • qq_33951180
  • qq_33951180
  • 2016-09-04 22:56:46
  • 1193

string类的引用计数的写时拷贝分析

写时拷贝(copy-on-write) 使用了引用计数的复制方法,在复制的时候会有一个变量来保存引用的次数,类似于: 假设A要管理S1这块空间,然后B也想要管理使用S1,写...
  • Bella_wx
  • Bella_wx
  • 2017-09-13 18:29:53
  • 72
收藏助手
不良信息举报
您举报文章:string类模拟之引用计数和写时拷贝
举报原因:
原因补充:

(最多只允许输入30个字)