浅拷贝与深拷贝

·浅拷贝例子

之前我们写过一个String类的基本封装,现在我们看下面的这个例子:

#include<iostream>

class String
{
public:
	String(const char *str="")
		:_pstr(new char[strlen(str)+1])
	{
		strcpy(_pstr, str);
	}

	~String()
	{
		if (_pstr)
		{
			delete[] _pstr;
		}
	}
private:
	char *_pstr;
};

int main()
{
	String str1("hello");
	String str2(str1);
	return 0;
}

编译虽然会通过,但是一旦运行就会报错。原因是因为当类里面有指针对象时,拷贝构造和运算符重载只进行值拷贝,两个对象共用同一块空间,对象销毁时程序会发生内存访问违规。str2需要调用String类的拷贝构造函数来创建,由于未显示定义,因此使用默认的拷贝构造函数。两个实例指向同一个地址,第一个对象销毁时,那么第二个实例就无法访问到对应内存。

·什么是浅拷贝

浅拷贝也称为位拷贝,编译器只是将对象中的值采用基本类型值赋值的方式拷贝过来,如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,继续对资源进行操作的时候,就会发生访问违规。那么如何解决呢?

·深拷贝

String(const String& s)
		:_str(new char[strlen(s._str) + 1])
	{
		strcpy(_str, s._str);
	}

我们可以看到上面的拷贝构造函数new了一块新的内存空间,因此str1和str2虽然内容相同,但是他们地址不同,深拷贝的意思其实也就是将地址也进行拷贝,不同的实例分别开辟不同的内存空间,这样一旦某一个实例销毁后,便不会发生内存的违规访问了。

·String类的深拷贝的传统写法

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(new char[strlen(s._str) + 1])
	{	
		strcpy(_str, s._str);
	}

	void Print()
	{
		cout << _str << endl;
	}

	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;
	}

	friend ostream& operator<<(ostream& _cout, const String& s)
	{
		_cout << s._str;
		return _cout;
	}

	~String()
	{
		if (_str)
		{
			delete[]_str;
			_str = nullptr;
		}
	}

private:
	char *_str;
};


void TestString()
{
	String s1("hello world");
	String s2(s1);
	cout << s1 << endl;
	/*String s2;
	s2 = s1;*/
	s2.Print();
	/*cout << s1;*/
}
int main()
{
	TestString();
	system("pause");
	return 0;
}

·String类的深拷贝的现代写法

class String
{
public:
	String(const char * str = "")
		:_str(new char[strlen(str)+1])
	{
		strcpy(_str, str);
	}
	
	String(const String& str)
		:_str(NULL)
	{
		String tmpStr(str._str);
		swap(_str, tmpStr._str);
	}
	//借助构造函数
	/*String& operator=(const String& str)
	{
		if (this!=&str)
		{
			String tmpStr(str._str);
			swap(_str, tmpStr._str);
		}
		return *this;
	}*/
	//借助拷贝构造函数
	/*String& operator=(String str)
	{
		swap(_str, str._str);
		return *this;
	}*/
	~String()
	{
		if (_str)
		{
			delete[]_str;
		}
	}
	const char* c_str()
	{
		return _str;
	}
private:
	char * _str;
};

图示挖个坑o(╥﹏╥)o

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值