** 一, 浅拷贝:**
1) 代码:
1, 构造:
- String ::String(const char* str="")
- :_str(new char[strlen(str)+1])
- {
- strcpy(_str, str);
- }
2, 拷贝构造
- String::String(const String&s)
- : _str(s._str)
- {}
3, 赋值浅拷贝
- //s2==s1
- String& String:: operator=(const String&s)
- {
- if (this!=&s)
- {
- _str = s._str;
- }
- return *this;
- }
2) 图解:
4, 析构
- String::~String()
- {
- if (_str)
- {
- delete[] _str;
- }
- }
由于浅拷贝会引发析构两次的问题 所以引入了引用计数, 为了保证证每个对象的独立性, 所以引入了写时拷贝, 可以理解为引用计数和写时拷贝就是浅拷贝的一种优化.
二, 引用计数与写时拷贝:
1) 代码:
1, 构造:
- String::String(const char* str = "")// 拷贝
- :_str(new char[strlen(str)+1])
- ,_pCount(new int(1))// 开辟 1 块空间并初始化为 1
- {
- strcpy(_str, str);
- }
2, 拷贝构造:
- String::String(const String&s)// 拷贝构造
- :_str(s._str)
- ,_pCount(s._pCount)
- {
- (*_pCount)++;
- }
调试结果:
图解:
问题: 一个改了会影响另一个
- String s1("hello world");
- String s2(s1);
- s1[2] = 'x';
- cout <<s1.c_str() << endl;
- cout << s2.c_str() << endl;
调试结果:
3, 赋值运算符重载:
- //s2=s1
- String& String:: operator=(const String&s)// 赋值运算符重载
- {
- if (this != &s)
- {
- if (--(*_pCount) == 0)// 这里不调用析构函数,
- // 因为析构函数一般都是在出了函数作用域才被调用
- {
- delete[] _str;
- delete _pCount;
- }
- _str = s._str;
- _pCount = s._pCount;
- ++(*_pCount);
- }
- return *this;
- }
- String s1("hello world");
- String s2(s1);
- s1[2] = 'x';
- cout << s1.c_str() << endl;
- cout << s2.c_str() << endl;
调试结果:
图解:
4, 写时拷贝 (下开法):
- void String::CopyOnWrite()
- {
- if ((*_pCount)> 1)
- {
- char*newstr = new char[strlen(_str) + 1];
- strcpy(newstr, _str);
- _str = newstr;
- --(*_pCount);
- _pCount = new int(1);
- }
- }
- char& String::operator[](size_t pos)// 可以修改字符串中的字符
- {
- CopyOnWrite();
- return _str[pos];
- }
为了解决两个程序会相互影响
调试结果:
图解:
5, 析构:
- String::~String()
- {
- if (--(*_pCount)==0)
- {
- delete[] _str;
- delete _pCount;
- _str = NULL;
- _pCount = NULL;
- }
- }
三, 深拷贝 (传统写法和现代写法)
传统写法:
- String::String(const char*str = "")
- :_str(new char[strlen(str) + 1])
- {
- strcpy(_str, str);
- }
- //s2(s1)
- String::String(const String& s)
- : _str(new char[strlen(s._str)+1])
- {
- strcpy(_str, s._str);
- }
- //s3=s1
- String& String::operator=(const String&s)
- {
- if (this!=&s)
- {
- char*str = new char[strlen(_str) + 1];
- delete[] _str;
- _str = str;
- strcpy(_str, s._str);
- }
- return *this;
- }
- String::~String()
- {
- if (_str)
- {
- delete[] _str;
- }
- }
调试结果:
图解:
现代写法:
- String::String(const char*str = "")
- :_str(new char[strlen(str) + 1])
- {
- strcpy(_str, str);
- }
- //s2(s1)
- String::String(const String& s)
- : _str(NULL)
- {
- String tmp(s._str);
- swap(tmp._str, _str);
- }
- //s1=s3
- String& String::operator=(const String&s)
- {
- if (this != &s)
- {
- String tmp(s._str);
- swap(_str, tmp._str);
- }
- return *this;
- }
- String::~String()
- {
- if (_str)
- {
- delete[] _str;
- }
- }
调试结果:
图解:
补充写时拷贝 (头开法):
- String::String(const char* str = "")
- :_str(new char[strlen(str)+5])
- {
- _str += 4;
- strcpy(_str, str);
- *((int*)(_str-4)) = 1;
- }
- //s2(s1)
- String::String(const String& s)
- :_str(s._str)
- {
- *((int*)(_str-4)) += 1;
- }
- //s1=s2
- String& String ::operator=(const String& s)
- {
- if (this!=&s)
- {
- if (--(*(int*)(_str - 4)) == 0)
- {
- delete[](_str - 4);
- }
- _str = s._str;
- ++(*(int*)(_str - 4));
- }
- return *this;
- }
- void String::CopyOnWrite()
- {
- if ((*(int*)(_str-4))>1)
- {
- char* newstr = new char[strlen(_str) + 5];
- strcpy(newstr, _str);
- --(*(int*)(_str - 4));
- _str = newstr;
- ++(*(int*)(_str - 4));
- }
- }
- char &String::operator[](size_t pos)
- {
- CopyOnWrite();
- return _str[pos];
- }
- String::~String()
- {
- if (--(*(int*)(_str-4))==0)
- {
- delete[] (_str-4);
- }
- }
引用计数导致的改一块两块一块改的问题
写时拷贝:
调试结果:
图解:
来源: https://blog.csdn.net/adzn1/article/details/79867244