【C++】详解深浅拷贝的概念及其区别

🦄个人主页:修修修也

🎏所属专栏:C++

⚙️操作环境:Visual Studio 2022


目录

什么是拷贝

什么是浅拷贝

什么是深拷贝

深浅拷贝的区别及适用场景

写时拷贝

结语


什么是拷贝

        在C++编程中,拷贝是一个非常重要的概念,对于理解和使用类和对象起着至关重要的作用。

        当定义一个类时,我们显式地或隐式地指定在此类型的对象拷贝移动赋值销毁时做什么。一个类通过定义五种特殊的成员函数来控制这些操作,包括:拷贝构造函数( copy constructor)、拷贝赋值运算符( copy-assignment operator )、移动构造函数( moveconstructor)、移动赋值运算符(move-assignment operator)析构函数( destructor)

        拷贝和移动构造函数定义了当用同类型的另一个对象初始化本对象做什么拷贝和移动赋值运算符定义了将一个对象赋予同类型的另一个对象做什么。析构函数定义了当此类型对象销毁时做什么。我们称这些操作为拷贝控制操作(copy control)。

        如果一个类没有定义所有这些拷贝控制操作,编译器会自动为它定义缺失的操作。因此,很多类会忽略这些拷贝控制操作。但是,对一些类来说,依赖这些操作的默认定义会导致灾难 ! 通常,实现拷贝控制操作最困难的地方是首先认识到什么时候需要定义这些操作。
在定义任何C++类时,拷贝控制操作都是必要部分。

        简单来讲就是,基于面向对象语言对类的使用,我们自然的衍生出了需要将某个类对象值给另一类对象/用一个已存在的对象去初始化另一个正在声明的对象的情况,如:

class Date
{
public:
	//类函数声明or定义部分

	//成员变量
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	Date d2 = d1;
    Date d3(d1);

	return 0;
}

        这时我们就需要将已经存在的这个对象的内容"拷贝"给需要的地方,如下图:


什么是浅拷贝

        清楚了什么是拷贝后,我们来讲一下什么是浅拷贝.

        浅拷贝是指将一个对象的值赋给另一个对象时,只是简单地将对象的每个成员变量的值进行复制。这意味着两个对象的内容是完全一模一样,即:

        浅拷贝看似没有什么问题,但当我们面对含有指针类型成员变量的类时,浅拷贝就会出现一些严重的事故,浅拷贝使两个类对象共享相同的内存地址,当一个对象的值发生改变时,另一个对象的值也会相应地改变。这种拷贝方式在某些情况下可能会带来一些意想不到的问题,特别是当涉及到动态内存分配时,如:

class Stack
{
public:
	//类函数声明/定义部分

	//成员变量
private:
	int* arr;
	int top;
	int capacity;
};

        对于栈类,它有三个成员变量,一个是指向存储栈内数据位置的指针,还有两个是整型,当我们创建了一个类对象st1时,内存中的逻辑关系如下图:

        然而,当我们使用浅拷贝将st1拷贝给st2时,会出现这样的情况:

        从图中可以看出,浅拷贝后的st2中的内容是和st1一模一样的,连指针都指向同一块存储空间,这样两个类对象共享相同的内存地址,当一个对象的值发生改变时,另一个对象的值也会相应地改变。并且如果类对象中指向的这块空间原本是动态开辟的,那么当其中一个类对象析构时将这块空间释放,另一个类对象中存储的这个指针就是一个悬空指针,极容易造成非法访问问题,即便是不使用,也不能销毁,否则也会造成内存空间二次释放的问题.


什么是深拷贝

        深拷贝是一种比较安全和稳定的对象拷贝方式,它在拷贝时如果遇到指针类型的数据,不会像浅拷贝那样单纯的只赋值指针的位置,而是会重新动态开辟一块新的空间,然后将原指针指向空间的内容拷贝到自己新开辟的空间中,这样,原始对象和拷贝对象会拥有各自独立的内存空间,互不影响

        深拷贝可以避免因为对象指向同一块内存而导致的潜在问题,如对象析构时可能引发的内存泄漏指针悬空等情况。

        深拷贝图示如下:


深浅拷贝的区别及适用场景

        简单来说,浅拷贝就是单纯的一模一样复制类对象的内容,而深拷贝是对类对象的内容进行深层次的拷贝

        用阿拉丁神灯的故事给大家打个比方吧:

        浅拷贝的结果是这样的:

        而深拷贝的结果是这样的:

        通过前文我们对浅拷贝和深拷贝的了解,其实不难分析出,浅拷贝的适用场景是当类中不含有指针类型的成员变量的成员时(注意,类中如果包含其他类作为成员时,成员类也同样不应含有指针类型成员),在这种场景下使用浅拷贝就非常快捷且方便,不会有什么问题.

        而对于类中包含指针类型的成员变量时,特别是这个指针指向的是某块动态开辟的内存空间时,拷贝就必须使用深拷贝来实现,否则就会出现之前提到的指针悬空或内存泄漏等问题.


写时拷贝

        写入时复制是一种计算机程序设计领域的优化策略。其核心思想是,如果有多个调用者同时请求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这个过程对其他的调用者是透明的(transparently)。此作法的主要优点是如果调用者没有修改该资源,就不会有副本(private copy)被建立,因此多个调用者只是读取操作是可以共享同一份资源。

        写时拷贝详解文章:

【Linux】写时复制(CopyOnWrite)|写时拷贝|rcu


结语

希望这篇关于 深浅拷贝 的博客能对大家有所帮助,欢迎大佬们留言或私信与我交流.

学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!

相关文章推荐

【C++】动态内存管理

【C++】标准库类型string

【C++】构建第一个C++类:Date类

【C++】类的六大默认成员函数及其特性(万字详解)

【C++】内联函数

【C++】函数重载

【C++】什么是类与对象?

【C++】缺省参数(默认参数)

【C++】命名空间

  • 13
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

修修修也

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值