目录
浅拷贝
浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。要解决浅拷贝问题,C++中引入了深拷贝。
namespace sjj
{
class string
{
public:
string(const char* str)
:_str(new char[strlen(str)+1])// \0
{
strcpy(_str,str);//char *strcpy( char *strDestination, const char *strSource );
}
//此处没有写拷贝构造函数,会使用编译器默认生成的拷贝构造函数
//对于内置类型char* 完成值拷贝
~string()
{
delete[] _str;
_str = nullptr;
}
private:
char* _str;
};
void test()
{
string s1("hello");
string s2(s1);
}
}
浅拷贝就是值拷贝,像memcpy一样,只是把数据给拷贝过去
通过调试,在监视窗口我们也能验证确实两个指针的地址是一样的
这样就会在最后调用析构函数的时候出现问题,后定义的对象先析构,释放指针资源,s2的_str先释放了,但是两个对象里面的_str是一样的,当后析构释放s1的_str时候,s1的_str指向一块已经释放过的空间,现在它相对于野指针了,释放野指针就会导致程序崩溃
事实上我们想要达成的目标是,两个对象中的_str分别指向两块不同的空间,拷贝时再将数据拷贝到另外一块空间上面去,这里就要引出我们的深拷贝了
深拷贝
如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式(就是要手动写,不能用编译器自动生成的)给出。一般情况这些函数都是按照深拷贝方式提供。
这样一来两块空间相互独立,s2的_str和s1的_str调用析构函数释放资源时互不影响,各种对于数据的增删查改也不会影响
所以对于string类这样的类,我们就不能用编译器默认生成的,因为是值拷贝的,所以我们要自己手动写
namespace sjj
{
class string
{
public:
string(const char* str)
:_str(new char[strlen(str)+1])// \0
{
strcpy(_str,str);//char *strcpy( char *strDestination, const char *strSource );
}
//要用自己写的
string(const string& s)
:_str(new char[strlen(s._str)+1])
{
strcpy(_str,s._str);
}
~string()
{
delete[] _str;
_str = nullptr;
}
private:
char* _str;
};
void test()
{
string s1("hello");
string s2(s1);//correct
}
}
我们可以再次打开监视窗口,观察两个指针的值:
可以验证到确实是两块不同的空间了!