当前位置:   article > 正文

深入了解string的深浅拷贝,写时拷贝_std::string 写时拷贝是不是去掉了

std::string 写时拷贝是不是去掉了

c++中类中有默认的构造函数,其中就有拷贝构造,默认的拷贝构造按照字节进行拷贝

按字节拷贝的问题在于:如果该空间为指针变量,且指向一块正在管理的空间,当浅拷贝之后,就会有两个变量同时管理这块空间,当生命周期结束后,也会随之析构两次,这是不允许的。
因此这种情况下,我们需要手动实现拷贝构造,简单来说,我们需要开辟空间,将原来管理的空间赋值一份,这样,一人一份就没有纠纷了。

下面来探索string的浅拷贝。

string如果默认支持的是浅拷贝的无疑是会出问题的,因此毫无疑问string中实现的不是浅拷贝。

其实string中有两种实现拷贝的方式, 深拷贝和写时拷贝,其中深拷贝分为传统写法和现代写法。

传统写法:每个需要进行拷贝的函数都自己创建空间,进行字节的拷贝。

现代写法:完成默认构造函数的正常写法(创建空间,按字节拷贝), 其余的拷贝构造,赋值运算符重载等函数,复用默认构造函数。从而提高代码复用性,也简化了我们的工作量。

写时拷贝:写时拷贝技术是通过"引用计数"实现的,在分配空间的时候多分配4个字节,用来记录有多少个指针指向块空间,当有新的指针指向这块空间时,引用计数加一,当要释放这块空间时,引用计数减一(假装释放),直到引用计数减为0时才真的释放掉这块空间。当有的指针要改变这块空间的值时,再为这个指针分配自己的空间(注意这时引用计数的变化,旧的空间的引用计数减一,新分配的空间引用计数加一)。

传统写法:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string.h>
namespace sstr {
	class string {
	public:
		string(const char* str = "") {
			// 构造string类对象时,如果传递nullptr指针,认为程序非法,此处断言下
			_str = new char[strlen(str) + 1];
			strcpy(_str, str);
		}
		string(const string& s)
			: _str(new char[strlen(s._str) + 1])
		{
			strcpy(_str, s._str);
		}
		string& operator=(const string& s){
			if (this != &s){
				char* pStr = new char[strlen(s._str) + 1];
				strcpy(pStr, s._str);
				delete[] _str;
				_str = pStr;
			}
			return *this;
		}
		~string(){
			if (_str){
				delete[] _str;
				_str = nullptr;
			}
		}
	private:
		char* _str;
	};
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

现代写法:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string.h>
#include <algorithm>
namespace sstring {
	class string {
	public:
		string(const char* str = "") {
			if (nullptr == str)
				str = "";
			_str = new char[strlen(str) + 1];
			strcpy(_str, str);
		}
		string(const string& s)
			: _str(nullptr)
		{
			string strTmp(s._str);
			std::swap(_str, strTmp._str);
		}
		// 对比两种实现方式
		string& operator=(string s){
			std::swap(_str, s._str);
			return *this;
		}
		/*
		string& operator=(const string& s){
		if(this != &s){
		string strTmp(s);
		swap(_str, strTmp._str);
		}
		return *this;
		}
		*/
		~string(){
			if (_str){
				delete[] _str;
				_str = nullptr;
			}
		}
	private:
		char* _str;
	};
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

写时拷贝:

class String
{
public:
	String(const char *str = "")
		:_str(new char[strlen(str) + 1 + 4])
	{
		cout << "Sring()" << endl;
		_str += 4;                            //前4个字节用来存放引用计数
		GetCount() = 1;                       //引用计数的初始值设置成1
		strcpy(_str, str);
	}
 
	String(String& s)
		:_str(s._str)
	{
		cout << "Sring(String&)" << endl;
		GetCount()++;
	}
 
	String& operator=(String& s)
	{
		cout << "Sring& operator=" << endl;
 
		if (this != &s)
		{
			Release();
			_str = s._str;
			GetCount()++;
		}
		return *this;
	}
 
	~String()
	{
		cout << "~Sring()" << endl;
		Release();
	}
public:
	char& operator[](size_t index)
	{
		if (GetCount() == 1)                   //如果计数器为1,则直接返回
		{
			return _str[index];
		}
		GetCount()--;
		char *tmp = _str;
		_str = new char[strlen(tmp) + 1 + 4];
		_str += 4;
		strcpy(_str, tmp);
		GetCount() = 1;
		return _str[index];
	}
private:
	int& GetCount()
	{
		return *(int *)(_str - 4);
	}
	void Release()
	{
		if (--GetCount() == 0)
		{
			cout << "释放" << endl;
			delete[](_str - 4);        //注意释放的时候还有 存放引用计数的4个字节
			_str = NULL;
		}
	}
private:
	char *_str;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/501761
推荐阅读
相关标签
  

闽ICP备14008679号