深拷贝和浅拷贝的区别
拷贝构造函数是用于将一个对象复制到新创建的对象中。
浅拷贝只是复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化,这就是浅拷贝
深拷贝是将对象及值复制过来,两个对象修改其中任意的值另一个值不会改变,这就是深拷贝
说明
C++类中存在默认的隐式拷贝构造函数,每当程序生成了对象副本时,编译器都将使用复制构造函数。这种默认的隐式构造函数是按值进行复制的,也就是说这种隐式拷贝构造函数为浅拷贝构造函数。
下面代码举例:
#include <iostream>
using namespace std;
class test{
public:
test(const char* str){
a = strlen(str);//改为sizeof就是错的
newStr = new char[a + 1];
strcpy(newStr, str);
g += 1;
cout << "第" << g << "次调用:";
cout <<"test构造测试:" << newStr << endl;
}
~test(){
x += 1;
cout << "第" << x << "次调用:";
cout << "test析构测试:"<< newStr << endl;
delete [] newStr;
newStr = nullptr;
}
friend ostream& operator<<(ostream &out, const test& t){
out << t.newStr << endl;
return out;
}
char* retStr()const{
return newStr;
}
private:
int a;
char* newStr;
static int g; //计算调用几次构造函数
static int x;//计算调用几次析构函数
};
int test::g = 0;
int test::x = 0;
void callStr(test ts){
cout << "String value:\n";
cout <<"callStr函数:"<< ts.retStr() << endl;
}
int main(){
test t1("aaaaaaa1");
test t2("bbbbbbb2");
callStr(t1);
test t3 = "ccccccc3";
return 0;
}
这里可以发现构造函数调用了3次,析构函数却调用了4次,且第4次构造函数是乱码。
在调用callStr(test ts)函数时,test类创建一个临时变量ts通过C++默认的拷贝构造函数来获取t1的值(函数结束就释放,调用一次析构函数),这里并没有调用我创建的构造函数,所以构造函数会比析构函数少一次。
因为是浅拷贝,是通过值进行传递。等同如下:
ts.str = t1.str;
ts与t1两个指向同一个地址的字符串,当函数callStr结束时,ts也会被释放,自动的调用析构函数。又由于t1创建字符串的空间被释放了,所以t1类结束时没有办法在进行释放空间,最后会有乱码产生。
解决方案
不使用C++默认的拷贝构造函数,定义一个深拷贝构造函数来进行,在类中定义如下:
test(const test& str){
g += 1;
newStr = new char[a + 1];
strcpy(newStr, str.retStr());
cout << "第" << g << "次调用:";
cout << "test构造测试:" << newStr << endl;
}
总结
当类中包含了使用new初始化的指针成员时,应当定义一个深拷贝构造函数,来复制指向的数据,而不是指针。