您的位置:首页 > 编程语言 > C语言/C++

【C++】模拟实现string类(版本二:用写时拷贝来实现)

2016-08-21 11:29 435 查看
1.什么是写时拷贝

     介绍写时拷贝之前,我们得先了解一下深浅拷贝,浅拷贝简单来说就是:只是对指针的拷贝,拷贝后和原来的指针指向同一块空间,如图:







    所以,浅拷贝其实存在很多问题:
        1.由于都指向同一块空间,所以,一旦其中一个对其内容做了更改,则所有对象都会发生变化,显然这并不是我们想要的。
        2.很容易造成同一块空间被释放两次,因为都指向同一块空间。
        3.很容易造成内存泄漏
    深拷贝即不止对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。



     深拷贝解决了浅拷贝存在的那些问题,但是如果每次都给对象开辟内存,但是不一定会进行更改,岂不是会浪费内存?所以写时拷贝出现了
那么写时拷贝是什么意思呢?
   顾名思义,就是在程序要进行写入操作是进行深度拷贝,否则进行浅拷贝,设置一个引用计数(与空间绑定在一起),当又有新指针指向这块空间时,引用计数+1,析构时,先检测引用计数是否为1,若为1则直接释放,否则,引用计数-1即可。有兴趣的读者可以验证一下,在Windows下,string是用深度拷贝的方式实现的,但是在Linux下,string是用写时拷贝的方式实现的。
2.写时拷贝string的部分实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<cstring>
using namespace std;

class String
{
friend ostream &operator<<(ostream &os, const String & s);
public:
String(char *str = "")
:_str(new char [strlen(str) + 5]) //将引用计数器和字符串放在同一块空间
{
_str += 4;
GetCount()=1; //取到引用计数器的空间并赋为1.
strcpy(_str, str);
}
~String()
{
Release(); //为增强代码的复用性,封装了一个释放空间的函数
}
String(const String & s)
:_str(s._str)
{
GetCount()++;
}
String& operator=( String& s)
{
if (this != &s) //判断是否自己给自己赋值
{
Release();
_str = s._str;
++GetCount();
}
return *this;
}
char &operator[](size_t index) //写时,深度拷贝
{
if (GetCount() > 1)
{
GetCount()--;
char *tmp = new char[strlen(_str) + 5];
strcpy(tmp+4, _str);
_str = tmp+4;
GetCount()++;
}
return _str[index];
}
private:
int& GetCount() //得到引用计数空间并以引用的方式返回,方便计数器改变
{
return *(int *)(_str - 4);
}
void Release()
{
if (GetCount() == 0)
{
delete[](_str - 4);
}
}
private:
char* _str;
};
ostream &operator<<(ostream &os, const String & s)
{
os << s._str << "";
return os;
}
void test1()
{
String s1("hello");
String s2(s1);
String s3("world");
s2 = s3;
}

void test2()
{
String s("hello");
s[2] = 'q';
cout << s << endl;
}

int main()
{
test1();
test2();
getchar();
return 0;
}

    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: