string类的写时拷贝

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

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

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

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

[cpp] view plain copy

  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. if (_GetRefCount()>1)//当引用次数大于1时新开辟内存空间
  39. {
  40. --_GetRefCount();//原来得空间引用计数器减1
  41. char *str = new char[strlen(_str) + 5];
  42. strcpy(str+4, _str);
  43. _str = str+4;
  44. _GetRefCount()++;
  45. }
  46. return _str[index];
  47. }
  48. friend ostream& operator<<(ostream& output, const String& str)
  49. {
  50. output << str._str;
  51. return output;
  52. }
  53. private:
  54. int& _GetRefCount()
  55. {
  56. return *(int *)(_str - 4);
  57. }
  58. void _Release()
  59. {
  60. if (--_GetRefCount() == 0)
  61. {
  62. delete[] (_str-4);
  63. }
  64. }
  65. private:
  66. char *_str;
  67. };

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

将_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;
}
时间: 2024-10-16 09:25:21

string类的写时拷贝的相关文章

模仿实现C++库函数----String 类----用 写时拷贝 &nbsp; 实现

#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include<assert.h> #define DEFAULTNUME 3 using namespace std; class String { public: int& GetCount() { return *(((int *)_str) - 1); } char* GetStr() { return _str; } //找到字符 ch  并返回它的下标 i

string类的写时才拷贝(Copy-On-Write)

写时才拷贝(Copy-On-Write)的原理是什么? Copy-On-Write,其实是使用了一个计数器.当第一个类构造时,计数器初始值为1,string类的构造函数会根据传入的参数从堆上分配内存,当其他类需要这块内存时,这个计数器自动累加.当有析构函数时,这个计数器会减1,直到当计数器为1时,即最后一个类析构.此时,程序才会真正的delete这块从堆上分配的内存. 2.  string在什么情况下会发生写时才拷贝(Copy-On-Write)? 当string类中发生内存共享且内容发生改变时

String 类的实现(4)写时拷贝浅析

由于释放内存空间,开辟内存空间时花费时间,因此,在我们在不需要写,只是读的时候就可以不用新开辟内存空间,就用浅拷贝的方式创建对象,当我们需要写的时候才去新开辟内存空间.这种方法就是写时拷贝.这也是一种解决由于浅拷贝使多个对象共用一块内存地址,调用析构函数时导致一块内存被多次释放,导致程序奔溃的问题.这种方法同样需要用到引用计数:使用int *保存引用计数:采用所申请的4个字节空间. 1 #include<iostream> 2 #include<stdlib.h> 3 using

C++ String类写时拷贝

    维基百科:     写入时复制(英语:Copy-on-write,简称COW)是一种计算机程序设计领域的优化策略.其核心思想是,如果有多个调用者(callers)同时要求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变.这过程对其他的调用者都是透明的(transparently).此作法主要的优点是如果调用者没有修

标准C++类std::string的内存共享和Copy-On-Write(写时拷贝)

标准C++类std::string的内存共享,值得体会: 详见大牛:https://www.douban.com/group/topic/19621165/ 顾名思义,内存共享,就是两个乃至更多的对象,共同使用一块内存: 1.关于string的内存共享问题: 通常,string类中必有一个私有成员,其是一个char*,用户记录从堆上分配内存的地址,其在构造时分配内存,在析构时释放内存. 因为是从堆上分配内存,所以string类在维护这块内存上是格外小心的,string类在返回这块内存地址时,只返

简单的String类实现及写时拷贝

#include<iostream> using namespace std; class String { public: /*String(const char* str=" ") :_str(new char[strlen(str)+1]) { strcpy(_str, str); } */ String(const char* str = " ") { if (str == NULL) { _str = new char; _str[0] = '

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

浅拷贝:多个指针指向同一块空间,多次析构同一块内存空间,系统会崩溃.(浅拷贝就是值拷贝) 深拷贝:给指针开辟新的空间,把内容拷贝进去,每个指针都指向自己的内存空间,析构时不会内存崩溃. #include <iostream> #include <string> using namespace std; class String { public: String(const char*str) :_str(new char [strlen(str)+1]) { strcpy(_str

C++ String 写时拷贝

当类里面有指针对象时,采用简单的赋值浅拷贝,使得两个指针指向同一块内存,则析构两次,存在内存奔溃的问题,因此浅拷贝中利用引用计数. //引用计数浅拷贝 class String { public:  String(char*str = "")   :_str(new char[strlen(str) + 1])   , _pRefCount(new int(1))  {}  String(const String & s)   :_str(s._str)   , _pRefCo

String写时拷贝实现

头文件部分 1 /* 2 版权信息:狼 3 文件名称:String.h 4 文件标识: 5 摘 要:对于上版本简易的String进行优化跟进. 6 改进 7 1.(将小块内存问题与大块分别对待)小内存块每个对象都有,当内存需求大于定义大小时利用动态分配 8 2.实现大块内存的写时拷贝功能,提高效率,优化空间利用 9 3.类似new[]实现机制:将动态内存块大小信息保存为隐藏“头” 10 11 当前版本:1.2 12 修 改 者:狼 13 完成日期:2015-12-12 14 15 取代版本:1.