【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;
}
介绍写时拷贝之前,我们得先了解一下深浅拷贝,浅拷贝简单来说就是:只是对指针的拷贝,拷贝后和原来的指针指向同一块空间,如图:
所以,浅拷贝其实存在很多问题:
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;
}
相关文章推荐
- 【C++】面试题:模拟实现string类(版本一:用深度拷贝来实现 )
- 【C++】简单实现String类--深拷贝的普通版本和简洁版本
- 【C++】模拟string类的实现(string 类的深拷贝)
- 详解C++中String类模拟实现以及深拷贝浅拷贝
- 【C++】浅析浅拷贝,深拷贝及写时拷贝(copy_on_write),模拟实现String类。
- C++中String类模拟实现以及深拷贝浅拷贝
- c++ 深拷贝string类 简单实现
- string类写时拷贝的模拟实现
- C++ 中string类的三种模拟实现方式
- 【c++】模拟实现string类__实现增删查改
- 写时拷贝的方式实现C++中string类
- String类深拷贝的模拟实现
- 模拟实现String类(2)——写时拷贝
- C++【拷贝构造】和【拷贝赋值】(实现自定义的string类)
- C++面试题之模拟实现string类
- 模拟实现string深拷贝的两个版本
- 设计模式之 原型模式(prototype)(C++实现 深拷贝 + 浅拷贝版本[bug])
- 请用c++ 实现stl中的string类,实现构造,拷贝构造,析构,赋值,比较,字符串相加,获取长度及子串等功能。
- C++ 中string类的三种模拟实现方式
- 【String类浅拷贝的实现】C++:String类引用计数浅拷贝的两种实现