无论是浅拷贝还是深拷贝,最重要的是考虑内存的变化,不同语言对不同变量的操作也许不同,但是归根结底是改变的只是内存。深拷贝是实实在在复制了一样的一份到内存中,而浅拷贝则类似于快捷方式。由于数据类型的不同,造成深浅拷贝的难点,下文内容可能与事实存在出入,当我完全理解后,会将这句话删除。
无法使用“变量是盒子”做解释,应该把变量视作便利贴。
——《流畅的python》(虽然是我在python书上看到的,但对于变量的理解是类似的)
1.C++篇
之前对浅拷贝和深拷贝的概念都有所模糊,当我看到“浅拷贝是简单的赋值操作”,或是“在类中调用了两次析构”,总是无法理解,今天就来好好盘一盘。
先来说一下总结,我最近终于想明白了:浅拷贝就是简单的值拷贝,如int i = 4
类型,i在内存当中的值就是4,所以浅拷贝得到的也是4,但是如果是指针int *p = &i
,p在内存当中存放的值是一个地址,那么拷贝得到的就是这个地址;然而深拷贝则是一个完全的复制。
1. 预备知识
看了大佬的博客,才发现要理解浅拷贝和深拷贝,首先要了解数据在内存中的存储方式,本文打算用最简单直白的方式陈述清其中的关系,若想了解详细,可看文末的参考链接。
基本类型和引用类型
基本类型:就像你跟你朋友路过你家,你跟你朋友说,这就是我家房子,你家房子的外观、家具,真真切切展现在你们面前。
引用类型(蕴含指针):就像你给你朋友一个你家的地址(和照片),你跟你朋友说这是我家,但是你得到哪哪哪才能看到我有哪些家具。
2. 浅拷贝
简单的赋值拷贝操作,但对于基本类型和引用类型存在不同的情况。
基本类型
赋的是数据,不存在深拷贝和浅拷贝的问题.
如:
int x = 100;
int y = x; //此时x和y都是100;
如果要改变y的值,x的值不会改变。
引用类型
赋的值地址(就是引用类型变量在内存中保存的内容)。
如:
int* arr1 = new int[5]{1, 2, 3, 4, 5};
int* arr2 = arr1;//这就是一个最简单的浅拷贝
改变arr2所引用的数据:arr2[0]=100时,那么arr1[0]的值也是100。
浅拷贝总结
3. 深拷贝
在堆区重新申请空间,进行拷贝操作。
// 拷贝构造函数实现
STRING( const STRING& s )
{
//_str = s._str;
_str = new char[strlen(s._str) + 1]; // 开辟一个新的内存空间
strcpy_s( _str, strlen(s._str) + 1, s._str ); // 将旧值赋值在新内存空间上
}
STRING& operator=(const STRING& s)
{
if (this != &s) // 保证当前所指并非原对象
{
//this->_str = s._str;
delete[] _str;
this->_str = new char[strlen(s._str) + 1];
strcpy_s(this->_str, strlen(s._str) + 1, s._str);
}
return *this;
}
4. 拷贝函数
参考链接
面试题:深拷贝和浅拷贝(超级详细,有内存图)
C++细节 深拷贝和浅拷贝(位拷贝)详解
2. 扩展python篇(矩阵拷贝)
np.copy其实是一个深拷贝。
import numpy as np
a = np.ones((2, 2))
print(a)
"""
[[1. 1.]
[1. 1.]]
"""
print(id(a)) # id(a)获取变量的内存地址
"""
2433214758320
"""
# 浅拷贝(直接赋值)其实是对变量的直接引用-------------------------
b = a
print(b)
"""
[[1. 1.]
[1. 1.]]
"""
b = np.append(b, [1, 1])
print(b, id(b))
"""
[1. 1. 1. 1. 1. 1.] 2433217421360
"""
# 深拷贝(np.copy):拷贝父对象,不会拷贝对象的内部的子对象------------
c = np.copy(a) # 等价于 c = a.copy()
print(c)
"""
[[1. 1.]
[1. 1.]]
"""
print(id(c))
"""
2433215549872
"""
c = np.concatenate((c, np.ones((3, 2)) * 2), axis=0)
c *= 2
print(c, id(c))
"""
[[2. 2.]
[2. 2.]
[4. 4.]
[4. 4.]
[4. 4.]] 2433214757648
"""
print(a, id(a))
"""
[[1. 1.]
[1. 1.]] 2433214758320
"""