·浅拷贝例子
之前我们写过一个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