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 }

運行結果如下:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM