定义一个string类,未显式给出它的拷贝构造函数
class string
{
public:
string(const char* str="")
:_str(new char[strlen(str)+1])
{
strcpy(_str,str);
}
~string()
{
if(_str)
{
delete[] _str;
}
}
private:
char* _str;
};
void test()
{
string s1("peppa");
string s2(s1);
}
我们在类中没有显式地声明一个拷贝构造函数,那么,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的位拷贝。位拷贝又称浅拷贝。
浅拷贝只是简单的值拷贝,使s2.str=s1.str,两个指针就会指向同一块空间,其中一个修改,另一个也会受到影响,最致命的是,当一个对象析构时,就会释放他们两的公共空间,另一个指针就会变成野指针,再对其进行操作就会出现运行错误。
一般情况下我们不会使用系统合成的拷贝构造函数,自行定义:
class string
{
public:
//构造……
string(const string& s)
:_str(new char[strlen(s._str)+1])
{
strcpy(_str,s._str);
}
//析构……
private:
char* _str;
};
在我们自定义的拷贝构造函数中应该为新对象重新开辟一块空间,再将旧对象的内容拷贝过来。
深拷贝:也就是为每个对象分配独立的资源。保证多个对象不会因为共享资源在多次释放时造成程序崩溃的问题。
总结:一些情况下,类中的成员变量需要动态申请堆内存空间,若进行浅拷贝,就是把对象中的值完全赋给另一个对象,使得两个对象共同拥有同一块内存空间,其中一个对其释放,另一个再操作就会出问题。
因此一旦涉及资源申请,就需要我们人为给出拷贝构造函数,进行深拷贝。
系统合成的赋值运算符也是浅拷贝方式,必要时要自己给出。
深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。