版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_40921797/article/details/82634158
什么是写时拷贝
我们在只前的博客中讲述了深拷贝的写法string的深拷贝现代写法,我们window下vs就采用的就是深拷贝,而linux平台下则是采用写时拷贝的写法。写时拷贝顾名思义,就是写的时候再进行拷贝。也就是说,当我们拷贝构造或者赋值的时候,实际上只进行的浅拷贝,两个指针指向的是同一块new的空间而且拿了一块空间来做计数,记录着已经有多少指针同时指向这块空间了。当我们需要修改这个空间内容的时候,为了避免其他的对象对于的值也发生改变,则这时才给这个需要写的对象new一个新的空间,经常写操作。
写时计数
我们有很多类中记录有多少对象指向同一块空间,static 静态成员可以,但是这又一个问题,就是无论有几个new的空间,共用一个new计数,不错才怪。为了让这个计数器一直只跟着对应的一个new空间,我们采取开辟空间的时候多开辟4个,用来计数,实际的strcpy操作,是成员变量自加了一个int整形类型大小后才进行的。
具体实现代码:
#pragma once
// 1.现代写法写时拷贝
#include<iostream>
#include<string>
using namespace std;
#pragma warning (disable:4996)
class String
{
public:
String(const char* str = "")
:_str(new char[strlen(str)+1+4]),
_size(strlen(str)),
_capacity (_size)
{
int *pstr = (int *)_str;
*pstr = 1;
_str = _str + 4;
strcpy(_str, str);
}
// s1.Swap(s2);
void Swap(String& s)
{
swap(this->_str, s._str);
swap(_size, s._size);
swap(_capacity, s._capacity);
}
// String s2(s1)
String(const String& s)
:_str(s._str),
_size(strlen(s._str)),
_capacity(strlen(s._str))
{
int *pstr = (int *)(_str - 4);
*pstr += 1;
}
// s1 = s2
String& operator=(String s)
{
if (this->_str != s._str)
{
swap(_str, s._str);
_size = s._size;
_capacity = s._capacity;
}
return *this;
}
~String()
{
_str = _str - 4;
int* pstr = (int *)_str;
if (--(*pstr) == 0)
{
delete[]_str;
_str = NULL;
_size = 0;
_capacity = 0;
}
}
const char* c_str()
{
return _str;
}
void Expand(size_t n)
{
_capacity += n;
char * tmp = new char[_capacity+1+4];
int * ptmp = (int *)tmp;
*ptmp = (int)(*(_str - 4));
tmp = tmp + 4;
strcpy(tmp, _str);
swap(tmp, _str);
}
void PushBack(char ch)
{
int *pstr = (int *)(_str - 4);
if (*pstr > 1)
{
String tmp(_str);
swap(_str, tmp._str);
}
if (_size >= _capacity)
{
Expand(10);
}
_str[_size++] = ch;
_str[_size] = '\0';
}
void PushBack(const char* str)
{
int *pstr = (int *)(_str - 4);
if (*pstr > 1)
{
String tmp(_str);
swap(_str, tmp._str);
}
if (_size + strlen(str) >= _capacity)
{
Expand(strlen(str));
}
strcpy((_str + _size), str);
_size += strlen(str);
}
void PopBack()
{
int *pstr = (int *)(_str - 4);
if (*pstr > 1)
{
String tmp(_str);
swap(_str, tmp._str);
}
_size--;
_str[_size] = '\0';
}
void Insert(size_t pos, char ch)
{
int *pstr = (int *)(_str - 4);
if (*pstr > 1)
{
String tmp(_str);
swap(_str, tmp._str);
}
if (_size + 1 >= _capacity)
{
Expand(10);
}
assert(pos >= 0 && pos <= _size);
memmove(_str + pos+1, _str + pos,_size - pos+1);
_str[pos] = ch;
_size++;
}
void Insert(size_t pos, const char* str)
{
int *pstr = (int *)(_str - 4);
if (*pstr > 1)
{
String tmp(_str);
swap(_str, tmp._str);
}
if (_size + strlen(str) >= _capacity)
{
Expand(strlen(str));
}
assert(pos >= 0 && pos <= _size);
memmove(_str + pos + strlen(str), _str + pos,_size - pos+1);
strncpy(_str + pos, str, strlen(str));
_size += strlen(str);
}
void Erase(size_t pos, size_t n = 1)
{
int *pstr = (int *)(_str - 4);
if (*pstr > 1)
{
String tmp(_str);
swap(_str, tmp._str);
}
assert(pos >= 0 && pos < _size);
strcpy(_str + pos, _str + pos + 1);
_size -= 1;
}
size_t Find(char ch)
{
for (int i = 0; i <(int) _size; i++)
{
if (_str[i] == ch)
return i;
}
return -1;
}
size_t Find(const char* str)
{
return Find(strstr(_str, str));
}// ?
// s1 + 'a'
String operator+(char ch)
{
String tmp(_str);
tmp.PushBack(ch);
return tmp;
}
String& operator+=(char ch)
{
PushBack(ch);
return *this;
}
String operator+(const char* str)
{
String tmp(_str);
tmp.PushBack(str);
return tmp;
}
String& operator+=(const char* str)
{
PushBack(str);
return *this;
}
bool operator>(const String& s)
{
if (strcmp(_str, s._str) > 0)
return true;
else return false;
}
bool operator>=(const String& s)
{
return !(*this < s);
}
bool operator<(const String& s)
{
if (strcmp(_str, s._str) < 0)
return true;
else return false;
}
bool operator<=(const String& s)
{
return !(*this > s);
}
bool operator==(const String& s)
{
if (strcmp(_str, s._str) == 0)
return true;
else return false;
}
bool operator!=(const String& s)
{
return !(*this == s);
}
friend ostream& operator<<(ostream& cout, const String&s);
private:
char* _str;
size_t _size;
size_t _capacity;
};
ostream & operator<<(ostream &cout, const String&s)
{
cout << s._str;
return cout;
}