持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情
(欢迎大家关注我的微信公众号——控制工程研习,上面会分享很多我学习过程中总结的笔记。)
区别:
浅拷贝 | 深拷贝 | |
---|---|---|
1 | 在浅拷贝中,存储原始对象的副本,最终仅复制引用地址。 | 在深拷贝中,将存储原始对象的副本和重复的副本。 |
2 | 浅拷贝比深拷贝更快。 | 深拷贝比浅拷贝慢。 |
3 | 在复制的对象中所做的更改也会反映在原始对象上,因为两个对象共享同一块内存。 | 在复制的对象中进行更改时,原始对象上不会反射。 |
4 | 它将对象的引用存储在主内存中。 | 它存储对象值的副本。 |
定义:
· 浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。
· 深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。
C++实验:
#include <iostream>
using namespace std;
class Test
{
public:
int a;
int* p;
Test(int x) // parameterized constructor
{
a = x;
p = new int[a];
}
Test(Test& t)// copy constrcutor
{
a = t.a;
p = t.p;
}
};
int main()
{
Test t(3);
Test t2(t);
}
在这里,我们有一个名为 Test的类,它有两个构造函数,即一个参数构造函数 Test(int x) 和一个拷贝构造函数 Test(Test& t) ,因为我们可以在一个类中定义多个构造函数,即构造函数重载。
在main()函数中,t对象使用参数构造函数构造,同时传入了参数3给x。该对象如下:
t2对象则通过拷贝构造函数,拷贝了t对象:
注意这个拷贝构造函数的操作结果:我们首先创建的对象“t”。因此,t2.a 分配为 3。然后,t2.p 分配为 t.p,所以 t2.p和t.p 将指向相同的内存地址。这就是浅拷贝。
这样是没有满足设计需求的(除非你的需求就是这样)。t2 对象应该有自己的的数组。这并不符合实际的操作需求。
因此,拷贝构造函数的问题在于,如果一个对象完成了动态内存分配(堆部分中的内存分配),那么拷贝构造函数将不会为其创建新的内存。它将指向相同的内存。所以,你必须小心这种事情。
所以,我们应该修改拷贝构造函数。方法就是在拷贝构造函数里直接创造一个新的数组,然后把被复制对象的数组里的值一个一个赋值过来:
#include <iostream>
using namespace std;
class Test
{
public:
int a;
int *p;
Test (int x)
{
a = x;
p = new int[a];
}
Test (Test & t)
{
a = t.a;
p = new int[a];
if (p)
{
for (int i = 0; i < a; i++)
{
p[i] = t.p[i];
}
}
}
};
int main()
{
Test t (5);
t.p[0] = 1;
Test t2 (t);
t2.p[0] = 5;
cout << "t: " << t.a << " " << t.p[0] << endl;
cout << "t2: " << t2.a << " " << t2.p[0] << endl;
}
运行结果:
这里t2对象中的p数组修改了值,也没有影响到t对象的参数值。这就是实现了深拷贝。所以需要注意的是,在复制数组/指针之类的参数时要注意这个问题,因为只是单纯的值传递不会容易出现错误。