C++ 浅拷贝和深拷贝

本文深入探讨了深拷贝与浅拷贝的区别,通过具体实例展示了在C++中如何实现深拷贝,特别是在涉及堆内存时的必要性。同时,文章还讨论了vector在扩容时的拷贝行为,以及自定义拷贝构造函数的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

拷贝构造函数默认的是浅拷贝。当不涉及到堆内存时用浅拷贝完全可以,否则就需要深拷贝了。

浅拷贝相当于一个箱子有多个钥匙,但其中一个人打开箱子取走箱子里的东西时,其他人是不知道的。

深拷贝是有多个箱子每个箱子对应一个钥匙,但一个人取走他的钥匙对应的箱子里的东西时,不会对其他人产生影响。

 

 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 }

运行结果如下:

 

转载于:https://www.cnblogs.com/xingkongyihao/p/10841582.html

设计并实现一个动态整型数组类Vect,要求: (1)实现构造函数重载,可以根据指定的元素个数动态创建初始值为0的整型数组,或根据指定的内置整型数组动态创建整型数组。 (2)设计拷贝构造函数析构函数,注意使用深拷贝。 (3)设计存取指定位置的数组元素的公有成员函数,并进行下标越界,若越界则输出“out of boundary”。 (4)设计获取数组元素个数的公有成员函数。 (5)设计用于输出数组元素的公有成员函数,元素之间以空格分隔,最后以换行符结束。 在main函数中按以下顺序操作: (1)根据内置的静态整型数组{1,2,3,4,5}构造数组对象v1,根据输入的整型数构造数组对象v2。 (2)调用Vect的成员函数依次输出v1v2的所有元素。 (3)输入指定的下标及对应的整型数,设置数组对象v1的指定元素。 (4)根据数组对象v1拷贝构造数组对象v3。 (5)调用Vect的成员函数依次输出v1v3的所有元素。 设计并实现一个动态整型数组类Vect,要求: (1)实现构造函数重载,可以根据指定的元素个数动态创建初始值为0的整型数组,或根据指定的内置整型数组动态创建整型数组。 (2)设计拷贝构造函数析构函数,注意使用深拷贝。 (3)设计存取指定位置的数组元素的公有成员函数,并进行下标越界,若越界则输出“out of boundary”。 (4)设计获取数组元素个数的公有成员函数。 (5)设计用于输出数组元素的公有成员函数,元素之间以空格分隔,最后以换行符结束。 在main函数中按以下顺序操作: (1)根据内置的静态整型数组{1,2,3,4,5}构造数组对象v1,根据输入的整型数构造数组对象v2。 (2)调用Vect的成员函数依次输出v1v2的所有元素。 (3)输入指定的下标及对应的整型数,设置数组对象v1的指定元素。 (4)根据数组对象v1拷贝构造数组对象v3。 (5)调用Vect的成员函数依次输出v1v3的所有元素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值