C++ 浅拷贝和深拷贝
拷贝构造函数默认的是浅拷贝。当不涉及到堆内存时用浅拷贝完全可以,否则就需要深拷贝了。
浅拷贝相当于一个箱子有多个钥匙,但其中一个人打开箱子取走箱子里的东西时,其他人是不知道的。
深拷贝是有多个箱子每个箱子对应一个钥匙,但一个人取走他的钥匙对应的箱子里的东西时,不会对其他人产生影响。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 class A{ 6 public: 7 A() { 8 cnt1++; 9 name = new char(20); 10 strcpy(name, "hello"); 11 cout << "A" << name << endl; 12 } 13 ~A() { 14 cnt2++; 15 cout << "~A" << name << endl; 16 delete name; 17 name = nullptr; 18 } 19 char *name; 20 static int cnt1; 21 static int cnt2; 22 }; 23 24 int A::cnt1 = 0; 25 int A::cnt2 = 0; 26 int main() { 27 28 { 29 A a; 30 A b(a); 31 } 32 33 cout << A::cnt1 << ' ' << A::cnt2 << endl; 34 return 0; 35 }
运行结果如下:
很明显对象b的name是一个空指针了,如果对空指针进行操作的话就会出现问题了。
所以涉及到堆内存时就需要自己实现拷贝构造函数了。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 class A{ 6 public: 7 A() { 8 cnt1++; 9 name = new char(20); 10 memmove(name, "hello", strlen("hello")); 11 cout << "A" << name << endl; 12 } 13 A(const A&b) { 14 name = new char(strlen(b.name)+1); 15 memmove(name, b.name, strlen(b.name)); 16 } 17 ~A() { 18 cnt2++; 19 cout << "~A" << name << endl; 20 delete name; 21 name = nullptr; 22 } 23 char *name; 24 static int cnt1; 25 static int cnt2; 26 }; 27 28 int A::cnt1 = 0; 29 int A::cnt2 = 0; 30 int main() { 31 32 { 33 A a; 34 A b(a); 35 } 36 37 return 0; 38 }
运行结果如下:
随便讨论下vector。
vector可以看成一个可变大小的数组,有两个属性size和capacity,分别是大小和容量。大小表示当前元素的数量,而容量是表示当前能容量的元素数量。
当push_back()时,如果size和capacity相同时,首先向内存申请capacity*2(这个基数一般在1.5~2.0之间)大小的内存。然后将当前的元素拷贝到新的内存中,在释放原来的内存。
这样如果vector的类型没有自己实现拷贝构造函数时,默认是浅拷贝,比如下面这样就会出现问题。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 class A{ 6 public: 7 A() { 8 cnt1++; 9 name = new char(20); 10 strcpy(name, "hello"); 11 cout << "A" << name << endl; 12 } 13 ~A() { 14 cnt2++; 15 cout << "~A" << name << endl; 16 delete name; 17 name = nullptr; 18 } 19 char *name; 20 static int cnt1; 21 static int cnt2; 22 }; 23 24 int A::cnt1 = 0; 25 int A::cnt2 = 0; 26 int main() { 27 { 28 vector<A> vs; 29 for(int i = 0; i < 4; i ++) { 30 A a; 31 vs.push_back(a); 32 cout <<"size:"<< vs.size() << ' ' << vs.capacity() << endl << endl; 33 } 34 } 35 cout << A::cnt1 << ' ' << A::cnt2 << endl; 36 return 0; 37 }
结果如下:
明显出现了问题,就如提示所言,产生了两次释放。
如果自己实现了拷贝构造函数就不同了。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 class A{ 6 public: 7 A() { 8 cnt1++; 9 name = new char(20); 10 strcpy(name, "hello"); 11 cout << "A" << name << endl; 12 } 13 A(const A&b) { 14 name = new char(strlen(b.name)+1); 15 strcpy(name, b.name); 16 } 17 ~A() { 18 cnt2++; 19 cout << "~A" << name << endl; 20 delete name; 21 name = nullptr; 22 } 23 char *name; 24 static int cnt1; 25 static int cnt2; 26 }; 27 28 int A::cnt1 = 0; 29 int A::cnt2 = 0; 30 int main() { 31 { 32 vector<A> vs; 33 for(int i = 0; i < 4; i ++) { 34 A a; 35 vs.push_back(a); 36 cout <<"size:"<< vs.size() << ' ' << vs.capacity() << endl << endl; 37 } 38 } 39 cout << A::cnt1 << ' ' << A::cnt2 << endl; 40 return 0; 41 }
运行结果如下: