拷貝構造函數默認的是淺拷貝。當不涉及到堆內存時用淺拷貝完全可以,否則就需要深拷貝了。
淺拷貝相當於一個箱子有多個鑰匙,但其中一個人打開箱子取走箱子里的東西時,其他人是不知道的。
深拷貝是有多個箱子每個箱子對應一個鑰匙,但一個人取走他的鑰匙對應的箱子里的東西時,不會對其他人產生影響。
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 }
運行結果如下: