C++的复制和拷贝构造函数

什么复制,看下面这个例子,来理解什么是复制

第一个例子
int main()
{int a = 2;int b = a;//实际是创建一个副本,他俩是独立的变量,它们有不同的内存地址(复制)b = 3;//是可以修改的std::cin.get();}第二个例子
struct Vector2
{float x, y;
};
int main()
{Vector2 a = { 2,3 };Vector2 b = a;  //复制的是值,是吧a的值给了b,他们是两个不同的变量,占用的是两个不同的内存b.x = 5;   //a中的x(a.x)还会是2std::cin.get();}第三个例子
struct Vector2
{float x, y;
};
int main()
{Vector2 *a = new Vector2();Vector2 *b = a;  //这里我们看起来是复制了一些东西,但是我没有复制实际的向量,这个实际向量包含了x , y变量,我们复制的是指针b++; //影响指针,不会影响a中的x,yb->x = 2; //因为a b是指向同一个内存地址,所以这里会影响到astd::cin.get();}
为了更好的理解复制,我们自己写一个Strng类的例子:

接下来我们了解什么是构造函数:

首先,是一种特殊构造函数,如果没有显式的实现,编译器就会自动生成。

class 类名
{
public:// 拷贝构造类名(const 类名& that){}
};

为了更好的理解复制,我们自己写一个Strng类的例子:

#include <iostream>
#include <string>class String
{
private:char* m_Buffer; //字符缓冲区unsigned int m_Size; //字符的大小
public:String(const char* string){m_Size = strlen(string); //得到长度m_Buffer = new char[m_Size+1];//加一个空终止符memcpy(m_Buffer,string, m_Size+1); //des  Src size}~String(){delete[] m_Buffer;}friend std::ostream& operator<<(std::ostream& stream, const String& string);//友元
};std::ostream& operator<<(std::ostream& stream, const String& string) //重载<<
{stream << string.m_Buffer;//需要成为友元之后才可以访问return stream;}
int main()
{String string = "dajian";String second = string;//复制std::cout << string << std::endl;std::cout << second << std::endl;std::cin.get();//会报错,为什么呢?
}

因为当我们复制这dajian是c++自动给我们做的是它将所有类的成员变量,将它复制到一个新的内存地址中,这个新的内存地址包含了second字符串,内存中有两个String(浅拷贝),他复制的是指针,这两个string中有相同的char* 的值,也就是这个m_Buffer的内存地址,对于这两个String对象来说是相同的(两个字符串指向完全相同的内存缓冲区),程序会奔溃,当我们执行完会,这两个String都被销毁了,就出现了douhle free的错误。

那我们应该怎么修改呢?那就是深拷贝

#include <iostream>
#include <string>class String
{
private:char* m_Buffer; //字符缓冲区unsigned int m_Size; //字符的大小
public:String(const char* string){m_Size = strlen(string); //得到长度m_Buffer = new char[m_Size+1];//加一个空终止符memcpy(m_Buffer,string, m_Size+1); //des  Src size}//默认的拷贝构造/*String(const String& other): m_Buffer(other.m_Buffer),m_Size(other.m_size){}*///深拷贝String(const String& other) : m_Size(other.m_Size){m_Buffer = new char[m_Size + 1];memcpy(m_Buffer, other.m_Buffer, m_Size + 1);}~String(){delete[] m_Buffer;}friend std::ostream& operator<<(std::ostream& stream, const String& string);//友元
};std::ostream& operator<<(std::ostream& stream, const String& string) //重载<<
{stream << string.m_Buffer;//需要成为友元之后才可以访问return stream;}void PrintString(const String& string)
{std::cout << string << std::endl;
}
int main()
{String string = "dajian";String second = string;//复制std::cout << string << std::endl;std::cout << second << std::endl;std::cin.get();}

总结:

拷贝构造的任务是什么

拷贝构造参数对象的所有成员变量挨个赋值给新对象的成员变量,一般情况下编译器自动生成的拷贝构造就能完全满足我们使用需求。

什么时候需要显式实现拷贝构造

当成员变量中有指针成员且指向了堆内存,就需要显式实现拷贝构造。

编译器自动生成的拷贝构造,只会对成员变量挨个赋值,如果成员员中有指针变量且指向堆内存,结果就两个对象的指针变量同时指向一份堆内存,当它们执行析构函数时,会把这块堆内存释放两次,产生 double free or corruption 的错误。

正确的做法应该是先给新对象的指针变量重新申请一份堆内存,然后把旧对象的指针变量所指向的内存拷贝到新对象的指针变量所指向的内存。

浅拷贝与深拷贝

当类中的成员有指针变量且指向堆内存时,浅拷贝与深拷贝才有区别

浅拷贝 成员指针 = 成员指针。

深拷贝 memcpy(成员指针,成员指针)。

编译器自动生成的拷贝构造函数就是浅拷贝(把对象的成员进行挨个赋值),如果对象的成员有指针且指向堆内存,浅拷贝就会出现douhle free 的错误

深拷贝是批对象的成员中有指针且指针指向堆内存,不对指针成员赋值,而重新分配一块内存,把内存中的数据拷贝过来。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/19673.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nginx配置文件中静态资源文件禁止通过目录查看

Nginx配置文件中静态资源文件禁止通过目录查看 nginx作为文件服务器访问静态资源时&#xff0c;默认是可以通过目录路径查看该目录下的所有文件的&#xff0c;这样会被检查出漏洞&#xff0c;容易造成静态资源泄露。 方案 location /images {autoindex off;autoindex_exact_…

03-树3 Tree Traversals Again(浙大数据结构PTA习题)

03-树3 Tree Traversals Again 分数 25 作者 陈越 An inorder binary tree traversal can be implemented in a non-recursive way with a stack. For example, suppose that when a 6-node binary tree (with the keys numbered from 1 to 6) is traversed, th…

C++ 变量类型思维导图梳理

目前了解了前端、后端&#xff0c;准备再学习一门稍微底层的语言&#xff0c;整好自己年龄也比较大了&#xff0c;学个C语言&#xff0c;等以后哪天找不到前后端的工作了&#xff0c;就去做个少儿编程老师&#xff0c;为切换赛道做准备。 1、数据类型 定义&#xff1a;给变量…

LeetCode739:每日温度

题目描述 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替。 解题思想 使用单…

数字化转型对企业来说意味着什么?

数字化转型是当今社会不可避免的趋势&#xff0c;它的发展其实是多方面因素影响导致的。首先&#xff0c;随着科技的迅速发展&#xff0c;人们对于信息获取和处理的需求越来越强烈&#xff0c;这促使了各行各业都要朝着数字化方向发展。其次&#xff0c;全球化的潮流让企业需要…

【Qt秘籍】[006]-Qt 的 Hello World程序-编程第一步

"Hello,World!" 中文意思是“你好&#xff0c;世界”。 因为 The C Programming Language 中使用它做为第一个演示程序&#xff0c;后来很多程序员在学习编程或进行设备调试时延续了这一习惯。 下面&#xff0c;我们也将演示Qt中的"Hello World!" 我们先创…

【揭秘】如何借助聚道云软件连接器,实现差旅管理新飞跃!

导语&#xff1a;在当今竞争激烈的市场环境下&#xff0c;高效的差旅管理已成为企业节省成本、提升员工满意度的关键。今天&#xff0c;我们将带您看看如何通过聚道云软件连接器将易快报与阿里商旅成功对接&#xff0c;实现了差旅申请单的同步等需求&#xff0c;为企业管理带来…

Java实现数据结构---数组

文章目录 概念存储原理数组的操作完整代码 概念 数组是&#xff08;Array&#xff09;是有限个相同类型的变量所组成的有序集合&#xff0c;数组中的每一个变量为称为元素。数组是最简单、最常用的数据结构。 数组下标从零开始。 存储原理 数组用一组连续的内存空间来存储一…

1. tomcat

tomcat 一、tomcat1、作用2、安装tomcat2.1 官方地址2.2 安装jdk2.3 安装tomcat2.4 tomcat相关文件2.5 启动2.6 测试部署java项目2.7 设置开机自启动 二、部署java项目流程1、拉取代码2、安装maven编译工具3、修改maven仓库地址4、部署项目运行环境5、编译项目6、部署项目7、通…

文章《Causal Inference for Knowledge Graph based Recommendation》阅读

文章《Causal Inference for Knowledge Graph based Recommendation》阅读 论文概况及动机&#xff08;Introduction&#xff09;问题形式化方法论Causal Intervention (C1)Model ImplementationU()f()协同过滤部分模型优化 Causal Inference &#xff08;C2&#xff09; Exper…

Kafka生产者消息异步发送并返回发送信息api编写教程

1.引入依赖&#xff08;pox.xml文件&#xff09; <dependencies> <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-clients</artifactId> <version>3.6.2</version> </dependency> </depende…

SQL入门详细教程

一、什么是SQL&#xff1f; SQL&#xff08;Structured Query Language&#xff0c;结构化查询语言&#xff09;是一种用于访问和操作数据库的标准语言。它用于查询、插入、更新和删除数据库中的数据&#xff0c;并且能够创建和修改数据库结构&#xff08;例如表、视图、索引等…

Python登录漏洞复现

Python登录漏洞复现 3.1 环境准备 1&#xff09;升级pip pip install --upgrade pip -i https://pypi.tuna.tsinghua.edu.cn/simple2&#xff09;安装ddddocr图形识别库 pip install ddddocr -i https://pypi.tuna.tsinghua.edu.cn/simple3&#xff09;安装requests网络请求…

伦敦金1手指的是什么?

就算没有进行过伦敦金投资&#xff0c;甚至是没有做过任何金融产品投资的朋友&#xff0c;相信也听过别人做交易决定&#xff0c;他们都是1手两手那样头买入。有些朋友就好奇了&#xff0c;这伦敦金1手指的是什么意思&#xff1f;下面我们就来讨论一下。 首先&#xff0c;如果我…

CDH6.3.2集成Flink1.12.2

一、Linux下载httpd服务并开启 yum install y httpd systemctl start httpd systemctl enable httpd 二、获取已制作好的安装包 flink-1.12.2-bin-scala_2.11.tar ​ FLINK_ON_YARN-1.12.2.jar ​ flink-shaded-hadoop-2-uber-3.0.0-cdh6.3.2-10.0.jar 三、集成CM 1.上传编…

ERV-Net:一种用于脑肿瘤分割的高效3D残差神经网络| 文献速递-深度学习肿瘤自动分割

Title 题目 ERV-Net: An efficient 3D residual neural network for brain tumor segmentation ERV-Net&#xff1a;一种用于脑肿瘤分割的高效3D残差神经网络 01 文献速递介绍 脑肿瘤在全球范围内是致命的&#xff0c;与其他类型的肿瘤相比。胶质瘤是最具侵略性的脑肿瘤类…

java opcua实现数据点位事件订阅

前言 之前写了一篇文章《Java实现OPC UA断连重连和数据监听》 里面有代码实现对点位订阅的实现,但是有些x需求下这么写感觉不太好,今天又更新一种订阅的实现方式,根据不同的场景需求选择更合适的方案。 教程 依赖 首先在maven项目种引入opc依赖 <dependency><g…

数据挖掘与机器学习——聚类算法

目录 无监督学习 聚类算法 概念&#xff1a; 功能&#xff1a; 应用场景&#xff1a; 评判标准&#xff1a; 划分聚类&#xff1a; K-means聚类 逻辑实现&#xff1a; 聚类方式 问题&#xff1a; 解决&#xff1a; 可能存在的问题&#xff1a; 1.初始值对K-means聚…

Ubuntu 22.04, 如何让VSCode中的cmakelist高亮显示

安装cmake插件即可。 CMakeLists.txt is not syntax highlighted Issue #534 microsoft/vscode-cmake-tools GitHub

CANOE制造dll文件,以及应用dll文件

1、使用canoe自带的capl dll 2、然后使用Visual Studio 2022 打开项目 3、项目打开后修改下项目属性 4、修改capldll.cpp文件 4.1 添加的内容 void CAPLEXPORT far CAPLPASCAL appSum(long i, long j, long* s){*s i j;} {"sum", (CAPL_FARCALL)appSum, "…