首先参考的是网友的讲非常不错:
https://blog.youkuaiyun.com/weixin_41143631/article/details/81486817
浅拷贝:位拷贝,拷贝构造函数,赋值重载
多个对象共用同一块资源,同一块资源释放多次,崩溃或者内存泄漏
深拷贝:每个对象共同拥有自己的资源,必须显式提供拷贝构造函数和赋值运算符。
简而言之:深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。
那么s啥时候需要调用拷贝构造函数呢?
一个对象以值传递的方式传入函数体
一个对象以值传递的方式从函数返回
一个对象需要通过另外一个对象进行初始化。
下面可以通过debug 进行单步调试|:
test1.cpp
#include <iostream>
#include <cstring>
using namespace std;
/***********************************************
* @brief:本段代码主要是用来说明C++拷贝构造函数中的深拷贝与浅拷贝
* @date:2019-06-15
***********************************************/
//实现类
class Array {
public:
Array()
{
cout << "array" << endl; //实现构造函数
}
Array(const Array & arr) //实现拷贝构造函数
{
m_iCount = arr.m_iCount;
cout << "Array&" << endl;
}
//析构
virtual ~Array()
{
cout << "~Array()" << endl;
}
//设置属性
void setCount(int _count)
{
m_iCount = _count;
}
int getCount()
{
return m_iCount;
}
private:
int m_iCount;
};
//test
int main()
{
Array arr1;
arr1.setCount(5);
cout << "arr1_m_iCount:" << arr1.getCount() << endl;
Array arr2(arr1); //实现的是浅拷贝
cout << "arr2_ m_iCount:" << arr2.getCount() << endl;
system("pause");
}
arr1[0] = 0x00fb10d2 {copy.exe!Array::`vector deleting destructor'(unsigned int)}
arr2[0] = 0x00fb10d2 {copy.exe!Array::`vector deleting destructor'(unsigned int)}
由此可以看出浅拷贝的特点就是,对象arr1 ,与arr2 都是指向同一个地址,而切同一个地址被析构两次;
我们在调用析构函数,释放内存空间的时候,两个对象指向的那块内存空间就会被释放两次,这样程序会奔溃,导致出错。
#include <iostream>
#include <cstring>
using namespace std;
/***********************************************
* @brief:本段代码主要是用来说明C++拷贝构造函数中的深拷贝与浅拷贝
* @date:2019-06-15
***********************************************/
//实现类
class Array {
public:
Array(int _count) //值传递
{
m_iCount = _count;
m_pArr = new int[m_iCount];
cout << "Array()" << endl;
}
Array(const Array & arr) //实现拷贝构造函数
{
m_iCount = arr.m_iCount;
m_pArr = arr.m_pArr;//浅拷贝
cout << "Array&" << endl;
}
//析构
virtual ~Array()
{
delete[]m_pArr;
m_pArr = NULL;
cout << "~Array()" << endl;
}
//设置属性
void setCount(int _count)
{
m_iCount = _count;
}
int getCount()
{
return m_iCount;
}
//打印地址
void printAddr()
{
cout << "m_pArr" << m_pArr << endl;
}
private:
int m_iCount;
int *m_pArr;
};
//test
int main()
{
Array arr1(5);
int qq= arr1.getCount();
Array arr2(arr1);
arr1.printAddr();
arr2.printAddr();
system("pause");
}
我们在类中添加一个数据成员int型的指针m_pArr,实例化一个对象arr1并给数据成员m_iCount赋值为5,与此同时系统也需要给另一个数据成员m_pArr在堆区分配内存空间
接着实例化一个对象arr2并将arr1的值复制给arr2,系统调用拷贝构造函数。将arr1.m_iCount赋值给arr2.m_iCount,将arr1.m_pArr赋值给arr2.m_iArr。因为在拷贝构造函数中,系统并没有在堆区分配一个内存空间给arr2的数据成员m_iArr。所以这里两个对象的数据成员m_iArr显然都指向了同一块内存空间.如果进行深拷贝:修改:
Array(const Array & arr) //实现拷贝构造函数
{
m_iCount = arr.m_iCount;
//m_pArr = arr.m_pArr;//浅拷贝
m_pArr = new int[m_iCount];
for (int i = 0; i < m_iCount; i++)
{
m_pArr[i] = arr.m_pArr[i];
}
cout << "Array&" << endl;
}
在C++中,下面三种对象需要拷贝的情况。因此,拷贝构造函数将会被调用。
1). 一个对象以值传递的方式传入函数体
2). 一个对象以值传递的方式从函数返回
3). 一个对象需要通过另外一个对象进行初始化