🦄个人主页:修修修也
🎏所属专栏: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一模一样的,连指针都指向同一块存储空间,这样两个类对象共享相同的内存地址,当一个对象的值发生改变时,另一个对象的值也会相应地改变。并且如果类对象中指向的这块空间原本是动态开辟的,那么当其中一个类对象析构时将这块空间释放,另一个类对象中存储的这个指针就是一个悬空指针,极容易造成非法访问问题,即便是不使用,也不能销毁,否则也会造成内存空间二次释放的问题.
什么是深拷贝
深拷贝是一种比较安全和稳定的对象拷贝方式,它在拷贝时如果遇到指针类型的数据,不会像浅拷贝那样单纯的只赋值指针的位置,而是会重新动态开辟一块新的空间,然后将原指针指向空间的内容拷贝到自己新开辟的空间中,这样,原始对象和拷贝对象会拥有各自独立的内存空间,互不影响。
深拷贝可以避免因为对象指向同一块内存而导致的潜在问题,如对象析构时可能引发的内存泄漏或指针悬空等情况。
深拷贝图示如下:
深浅拷贝的区别及适用场景
简单来说,浅拷贝就是单纯的一模一样复制类对象的内容,而深拷贝是对类对象的内容进行深层次的拷贝。
用阿拉丁神灯的故事给大家打个比方吧:
浅拷贝的结果是这样的:
而深拷贝的结果是这样的:
通过前文我们对浅拷贝和深拷贝的了解,其实不难分析出,浅拷贝的适用场景是当类中不含有指针类型的成员变量的成员时(注意,类中如果包含其他类作为成员时,成员类也同样不应含有指针类型成员),在这种场景下使用浅拷贝就非常快捷且方便,不会有什么问题.
而对于类中包含指针类型的成员变量时,特别是这个指针指向的是某块动态开辟的内存空间时,拷贝就必须使用深拷贝来实现,否则就会出现之前提到的指针悬空或内存泄漏等问题.
结语
希望这篇关于 深浅拷贝 的博客能对大家有所帮助,欢迎大佬们留言或私信与我交流.
学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!
相关文章推荐
【C++】动态内存管理
【C++】标准库类型string
【C++】构建第一个C++类:Date类
【C++】类的六大默认成员函数及其特性(万字详解)
【C++】内联函数
【C++】函数重载
【C++】什么是类与对象?
【C++】缺省参数(默认参数)
【C++】命名空间