C++编程语言中类对象的赋值与复制介绍(三)
本系列文章主要介绍 C++ 编程语言中类对象的赋值操作、复制操作,以及两者之间的区别,另外还会介绍“深拷贝”与“浅拷贝”的相关知识。
本文为系列文章的第三篇,主要介绍 C++ 编程语言中的“深拷贝”和“浅拷贝”,以及赋值运算符的重载、拷贝构造函数的重载的相关知识。
1 浅拷贝
1.1 What
浅拷贝:当进行对象拷贝时,只拷贝类中位于 stack 域中的内容,而不会拷贝 heap 域中的内容。
例如,使用类的默认的赋值运算符“=”,或默认的拷贝构造函数时,进行的对象拷贝都属于浅拷贝。这也说明,“浅拷贝”与使用哪种方式(赋值运算符或是拷贝构造函数)进行对象拷贝无关。
1.2 问题
浅拷贝会有一个问题,当类中存在指针成员变量时,进行浅拷贝后,目标对象与源对象的该指针成员变量将会指向同一块 heap 内存区域(而非每个对象单独占用一块内存区域),这就可能导致由于共用该段内存区域而产生内存覆盖、重复释放内存等问题。详情可参考本系列文章第一篇文章的相关内容。
所以,针对带有指针的类对象的拷贝操作,正确的做法是:使两个对象的指针各自指向不同的内存区域,即在拷贝时不是简单地拷贝指针,而是将指针指向的内存中的每一个元素都进行拷贝,由此也就引出了“深拷贝”的概念。
2 深拷贝
深拷贝:当进行对象拷贝时,将对象位于 stack 域和 heap 域中的数据都进行拷贝。
前面也提到了,类默认提供的赋值运算符或拷贝构造函数,进行的都是浅拷贝,所以,为了实现对象的深拷贝,需要对赋值运算符或拷贝构造函数进行重载,以达到深拷贝的目的。
2.1 赋值运算符的重载
这里展示一段重载赋值运算符的示例代码,内容如下:
// 重载赋值运算符ClassA& operaton=(const ClassA& obj){// 适应自赋值(obj = obj)操作if (this == &obj){return *this;}// 新建 heap 空间int iLength = strlen(str.m_pData);char* pTemp = new char[iLength + 1];// 新建 heap 空间成功后,再释放掉已有的 heap 空间// 保证异常安全性if (m_pszName != NULL){delete []m_pszName;m_pszName = NULL;}m_pszName = pTemp;// 拷贝 heap 空间的内容strcpy(m_pszName, obj.m_pszName);// 拷贝 stack 域的值m_nId = obj.m_nId;return *this;}private:int m_nId;char* m_pszName;
针对上面的赋值运算符重载函数,说明如下:
- 需要将函数返回值的类型声明为类的引用,同时函数返回实例自身的引用(*this)——只有返回一个引用,才可以允许连续赋值,如 a = b = c;
- 需要将入参的类型声明为常量引用(const 类名& 实例名),避免函数入参的拷贝构造函数调用,提高代码效率;
- 需要考虑自赋值情况;
- 需要释放实例自身已有的内存,避免内存泄漏;
- 需要考虑异常安全性,避免申请内存(new char)失败后,实例中的指针变为空指针,因此需要先执行申请内存操作,内存申请成功后,再释放实例的 heap 空间。
2.2 拷贝构造函数的重载
这里展示一段重载拷贝构造函数的示例代码,内容如下:
// 重载拷贝构造函数,重载后的拷贝构造函数支持深拷贝ClassA(ClassA &obj){// 拷贝 stack 域的值m_nId = obj.m_nId;// 新建 heap 空间m_pszName = new char[strlen(obj.m_pszName) + 1];// 拷贝 heap 空间的内容if (m_pszName != NULL){strcpy(m_pszName, obj.m_pszName);}}private:int m_nId;char* m_pszName;
2.3 总结
从上述两个示例代码可以看出,支持深拷贝的重载赋值运算符和重载拷贝构造函数相似,但两者也存在以下区别:
- 重载赋值运算符函数的返回值需要是对象的引用,以进行链式赋值(obj3 = obj2 = obj1);而重载拷贝构造函数因为属于构造函数的一种,所以不需要返回值;
- 重载赋值运算符函数要释放掉对象自身的 heap 空间(如果存在的话),以避免内存泄漏;而重载拷贝构造函数无需如此,因为拷贝构造函数函数是在创建(并初始化)对象时调用的,对象此时还没有分配 heap 空间;
- 如果在重载赋值运算符和重载拷贝构造函数都可以解决问题时,建议选择重载拷贝构造函数,因为后者貌似坑少一些:)。
C++编程语言中类对象的赋值与复制介绍(三)相关推荐
- 对象的赋值和复制(转)
一.对象的赋值和复制 1.对象的赋值 如果对一个类定义了两个或多个对象,则这些同类的对象之间可以互相赋值,或者说,一个对象的值可以赋给另一个同类的对象.这里所指的对象的值是指对象中所有数据成员的值. ...
- C++对象的赋值和复制
C++对象的赋值 1.1对象之间的赋值是用"="运算符来实现的,"="在c++中扩展为重载运算符来实现对象间的赋值. t1=t2; 1.2对象赋值是对数据成员的 ...
- python复制列表元素_Python学习教程:Python列表赋值,复制,深拷贝及5种浅拷贝详解...
Python学习教程:Python列表赋值,复制,深拷贝及5种浅拷贝详解 概述 在列表复制这个问题,看似简单的复制却有着许多的学问,尤其是对新手来说,理所当然的事情却并不如意,比如列表的赋值.复制.浅 ...
- java 对象复制 反射_利用Java反射机制实现对象相同字段的复制操作
一.如何实现不同类型对象之间的复制问题? 1.为什么会有这个问题? 近来在进行一个项目开发的时候,为了隐藏后端数据库表结构.同时也为了配合给前端一个更友好的API接口文档(swagger API文档) ...
- java两个对象赋值_一起学Java(二十六)----- 对象之间赋值
不积跬步,无以至千里:不积小流,无以成江海. Java语言基础 Java对象之间赋值 赋值是用等号运算符" = "进行的,在对对象进行"赋值"时,实际就是将句柄 ...
- 将对象的属性值复制到另一个对象中
将对象的属性值复制到另一个对象中 /**** 将第一个对象的属性值复制到第二个对象中* @param <T> 第一个对象* @param <R> 第二个对象*/ class H ...
- Java中类对象为空是什么意思?
Java中类对象为空是什么意思? 类对象为空并不等于该对象某一属性或多个属性为空,哪怕该对象所有属性为空也不能说明该对象就为空.一个类对象是否为空和它的属性没有关系. 类对象为空,要么该对象赋值为空, ...
- 通过反射为对象属性赋值
/// <summary>/// 通过反射为对象属性赋值/// </summary>/// <typeparam name="T">类型参数&l ...
- C++中对象的赋值拷贝构造函数
目录 1.对象与对象之间的赋值. 下面给出代码说明赋值语句 对象赋值的限制和特点 2.拷贝构造函数 拷贝构造函数的特点 自定义的拷贝构造函数的代码及运行结果 默认拷贝构造函数 调用拷贝构造函数的3种情 ...
- 1.19(对象类型判断、复制、in、遍历;深拷贝与浅拷贝;字符串的遍历接口、模板字符串、字符串扩展方法)
1.19(对象类型判断.复制.in.遍历;深浅拷贝;字符串的遍历接口.模板字符串.unicode.字符串扩展方法) 一.对象 1.属性简洁表示法与属性名表达式 let name = "wuy ...
最新文章
- 李飞飞:人工智能应用广泛 但场景理解不如2岁孩子
- Oracle11g数据库在win7系统上的安装教程
- mysql数据库导入外部数据乱码么_解决MySQL数据库导入导出数据乱码的问题
- Linux 自学大全,16张思维导图!
- 分布式实物实现方式_这是您完成实物产品设计任务的方式
- 数据结构杂谈(五)——栈
- python 数据库查询返回list或tuple
- android 自动打开qq,qq自动发消息脚本
- 小米路由器3 变砖 ttl 救砖,刷入padavan
- PreparedStatement 防止 SQL 注入原理
- 马克思主义基本原理概论第一章笔记
- Cortex-M0+电源管理
- openLayers 学习思维导图
- LTE(4G) - NR(5G) EPS承载
- Kafka学习笔记1
- 大文件MD5计算 C语言 (从OpenSSL库中分离算法:三)
- QT翻金币小游戏实现(三)
- 小米手机混淆升级崩溃记录与解决
- 【新】CSDN文章一键打印、输出PDF(自动阅读全文、全清爽模式)
- 项目 - 基于Docker Swarm的高可用Web集群