前言
在学习拷贝构造函数的时候遇到了深浅拷贝这个知识点 就写篇文章记录一下
(引用的部分不用太在意 是查的
(需要前提知识:知道默认拷贝构造函数是什么 知道默认拷贝构造函数和构造函数的关系、知道析构函数的写法和用处
浅拷贝
浅拷贝(Shallow Copy)是指创建一个新的对象,并将原始对象的非静态字段复制到新对象。如果字段是值类型的,那么对该字段执行复制;如果该字段是引用类型的,则复制引用但不复制引用的对象。这意味着原始对象和复制对象引用同一个对象,所以任何对复制对象的修改都可能影响到原始对象。因此,浅拷贝操作后的两个对象共享同一个底层数据源。
简单来说就是 逐个字节拷贝
被拷贝以及拷贝对象它们的值是完全相同的
深拷贝
深拷贝(Deep Copy)则是指创建一个完全独立的新对象,并递归地复制原始对象及其所有子对象。这意味着无论对象的层级有多深,新对象和原对象都是完全独立的。修改其中一个对象不会影响另一个对象。深拷贝会复制对象的所有层级,包括对象的属性、嵌套对象、引用等。
一般来说 涉及到动态开辟的对象在拷贝的时候 都需要深拷贝
对比
我们借助一段代码来比较深浅拷贝的区别 以及为什么要存在深拷贝
为没学栈的同学解释一下:下面这段代码就是创建了两个对象s1 和s2 然后将1、2、3、4逐个存入s1中 调用了默认拷贝构造函数将s1拷贝给s2 并且用的是浅拷贝的方式
typedef int DataType;
class Stack
{
public:
Stack(size_t capacity = 10)
{
_array = (DataType*)malloc(capacity * sizeof(DataType));
if (nullptr == _array)
{
perror("malloc申请空间失败");
return;
}
_size = 0;
_capacity = capacity;
}
void Push(const DataType& data)
{
// CheckCapacity();
_array[_size] = data;
_size++;
}
~Stack()
{
if (_array)
{
free(_array);
_array = nullptr;
_capacity = 0;
_size = 0;
}
}
private:
DataType* _array;
size_t _size;
size_t _capacity;
};
int main()
{
Stack s1;
s1.Push(1);
s1.Push(2);
s1.Push(3);
s1.Push(4);
Stack s2(s1);
return 0;
}
下面是s1和s2中array数组首元素指针的存储情况
根据浅拷贝逐字节拷贝的特点我们可以看出来 这两个array的地址是相同的 他们指向的是同一块空间
这就会导致在析构的时候 先释放了st2 再释放st1的时候就访问了野指针 程序直接崩溃
下面这段代码是深拷贝的写法
// Stack st2(st1);
//s就是st1 this是st2
Stack(const Stack& s)
{
DataType* tmp = (DataType*)malloc(s._capacity *(sizeof(DataType)));
if (tmp == nullptr)
{
perror("malloc fail");
exit(-1);
}
//上面几行看不懂的话不用管
memcpy(tmp, s._array, sizeof(DataType) * s._size);
_array = tmp;
_size = s._size;
_capacity = s._capacity;
}
而深拷贝则会根据array的大小 来开辟一块和array大小一样的空间 那么在析构的时候就没问题了
结论
所以在函数传参的时候 建议用引用 其次可以用指针 最不建议用传值
并且引用应该也是最方便的
结语
对于深浅拷贝的简单介绍到这里就结束了 后面会更深入的介绍 希望对你有帮助~~