String 类的实现写时拷贝浅析
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了String 类的实现写时拷贝浅析相关的知识,希望对你有一定的参考价值。
由于释放内存空间,开辟内存空间时花费时间,因此,在我们在不需要写,只是读的时候就可以不用新开辟内存空间,就用浅拷贝的方式创建对象,当我们需要写的时候才去新开辟内存空间。这种方法就是写时拷贝。这也是一种解决由于浅拷贝使多个对象共用一块内存地址,调用析构函数时导致一块内存被多次释放,导致程序奔溃的问题。这种方法同样需要用到引用计数:使用int *保存引用计数;采用所申请的4个字节空间。
1 #include<iostream>
2 #include<stdlib.h>
3 using namespace std;
4 class String
5 {
6 public:
7 String(const char *pStr = "")
8 {
9 if (pStr == NULL)
10 {
11 _pStr = new char[1 + 4];
12 *((int*)pStr) = 1;
13 _pStr = (char*)(((int*)_pStr) + 1);
14 *_pStr = ‘\\0‘;
15 }
16 else
17 {
18 _pStr = new char[my_strlen(pStr) + 1 + 4];
19 my_strcopy(_pStr, pStr);
20 *((int*)_pStr - 1) = 1;
21 }
22 }
23
24 String(const String& s)
25 :_pStr(s._pStr)
26 {
27 ++GetCount();
28 }
29
30 ~String()
31 {
32 Release();
33 }
34
35 String& operator=(const String& s)
36 {
37 if (this != &s)
38 {
39 Release();
40 _pStr = s._pStr;
41 --(GetCount());
42 }
43 return *this;
44 }
45
46 char& operator[](size_t index)//写时拷贝
47 {
48 if (GetCount() > 1) //当引用次数大于1时新开辟内存空间
49 {
50 char* pTem = new char[my_strlen(_pStr) + 1 + 4];
51 my_strcopy(pTem + 4, _pStr);
52 --GetCount(); //原来得空间引用计数器减1
53 _pStr = pTem + 4;
54 GetCount() = 1;
55 }
56 return _pStr[index];
57 }
58 const char& operator[](size_t index)const
59 {
60 return _pStr[index];
61 }
62 friend ostream& operator<<(ostream& output, const String& s)
63 {
64 output << s._pStr;
65 return output;
66 }
67 private:
68 int& GetCount()
69 {
70 return *((int*)_pStr - 1);
71 }
72 void Release()
73 {
74 if (_pStr && (0 == --GetCount()))
75 {
76 _pStr = (char*)((int*)_pStr - 1);
77 delete _pStr;
78 }
79 }
80
81 char *_pStr;
82 };
83
84 int main()
85 {
86 String s1;
87 String s2 = "1234";
88 String s3(s2);
89 s2[0] = ‘5‘;
90 String s4;
91 s3 = s4;
92 }
写时拷贝能减少不必要的内存操作,提高程序性能,但同时也是一把双刃剑,如果没按 stl 约定使用 String ,可能会导致极其严重的 bug ,而且通常是很隐蔽的,因为一般不会把注意力放到一个赋值语句。修改 String 数据时,先判断计数器是否为 0( 0 代表没有其他对象共享内存空间),为 0 则可以直接使用内存空间(如上例中的 s2 ),否则触发写时拷贝,计数 -1 ,拷贝一份数据出来修改,并且新的内存计数器置 0 ; string 对象析构时,如果计数器为 0 则释放内存空间,否则计数也要 -1 。
写时拷贝存在的线程安全问题
线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。String类写时拷贝可能存在的问题详见:http://blog.csdn.net/haoel/article/details/24077
以上是关于String 类的实现写时拷贝浅析的主要内容,如果未能解决你的问题,请参考以下文章