C++ 细节 彻底搞定深拷贝与浅拷贝

本文深入探讨了C++中深拷贝与浅拷贝的概念,通过实例对比了两种拷贝方式下对象行为的不同,强调了在资源管理中深拷贝的重要性。

首先参考的是网友的讲非常不错:

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). 一个对象需要通过另外一个对象进行初始化 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值