当前位置: 首页 > news >正文

c++ 拷贝构造

我们思考一下这个问题:

观察以下代码,在运行的时候会崩溃

想一想为什么

#include<iostream>
using namespace std;//栈类
typedef int DataType;
class Stack
{
public://默认构造:Stack(size_t capacity = 3){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc 申请空间失败!!!");return;}_capacity = capacity;_size = 0;}//压栈void Push(DataType data){//CheckCapacity();_array[_size] = data;_size++;	}//析构~Stack(){cout << "~Stack()" << endl;	free(_array);_array = nullptr;_size = _capacity = 0;}private:DataType* _array;int _capacity;int _size;};void func1(Date d)
{d.Print();
}void func2(Stack s)
{} int main()
{Stack s1;func2(s1);return 0;
}

在这里插入图片描述
为什么这种情况下编译的时候会报错?
因为你这里有一个主函数,主函数里面有一个栈类型的变量s1,然后呢这个主函数中我们使用了一个名为func2的函数。这个时候编译器就又会去建立一个func2函数的栈帧
这个时候要进行传参。
传值方式的传参是一种值的拷贝(或者叫做浅拷贝),意思就是把S1这个空间里的值直接拷贝到 func2这个函数栈帧中。
但是这个时候我们要注意。
我们在主函数的那个S1里面的成员变量_a是一个指针。指向了我们向内存申请的空间。如果我们把这个成员变量_a的值直接拷贝到func2函数中。那么func2函数中也会存取一份指针变量_a的所存的内容(即我们向内存所申请空间的地址)。
由于这是c++,当我们调用了func 2之后,在出这个函数的时候,它会自动调用析构函数。而析构函数会自动释放指针变量所指的那个空间
于是乎_a所指向的那个空间被我们释放掉了,当我们回到主函数的时候,我们使用完s1结束的时候会再次调用析构函数,这样的话,会造成对同一个空间的再一次释放,所以程序会崩溃。

如何解决:

引用:& (引用其实就是对变量取别名)

void func2(Stack &s)
{} 

如果我希望s的改变不去影响s1那该怎么办
即:你希望s 只是 s1 的拷贝
这个时候用一个对象去拷贝另外一个对象的时候,C++定义了一个函数来解决这样一个问题。
这个函数叫做拷贝构造
拷贝构造函数也是一个特殊的成员函数 其特征如下,

  1. 拷贝构造函数是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个,且必须是同类型对象 的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。(你如果不用引用的话,就会造成无穷递归)
    在这里插入图片描述

函数传参如果是内置类型,那就直接拷贝没问题
如果是自定义类型,则不能直接传,而是要调用一个函数来解决,这个函数就叫拷贝构造

为什么传值传参要调用拷贝构造函数?
为什么传值传参不能像c语言一样,结构体一样把相应的值依次的拷贝过去?

之前说了:像栈这样的类,如果你传值传参按浅拷贝的方式去拷贝的话,则会出现两次调用析构函数的情况,这会造成程序的崩溃。
所以这个时候我们必须要调用一个函数来解决这个问题,这个函数就是拷贝构造函数,他可以帮我们解决两次调用析构函数这个麻烦。这个拷贝构造函数可以完成深拷贝。

是不是有点懵,没关系,我们再来强调一下。

在c语言中,我们函数传值传参是直接拷贝的因为他不会出现一些问题
但是在c++中,如果我们直接拷贝的话,如果是栈这种类型对象的函数它会出现析构函数两次释放同一个空间的情况,
所以这个时候我们的拷贝就不能直接拷贝了,我们需要调用拷贝构造函数来进行拷贝。
我们使用拷贝构造函数来传参的话,那么函数它在传参的时候,它就不会直接传参,他会把参数先给拷贝构造函数,让拷贝构造函数处理完了之后再返回给函数,然后再进行函数中的内容。自定义类型传值传参必须调用拷贝构造。

就是在c++的逻辑中,任何传参都会先调用拷贝构造函数。
所以你会疑惑,为什么会造成深度递归呢?
因为当你使用函数的时候,拷贝构造函数和默认构造函数是构成函数重载的,那么当你调用这个函数的时候,你创建了一个d2嘛,那个d2面后面的括号里面写的是d1

那么他的这个形式是符合函数重载的形式的,这个时候他就会去调用拷贝构造函数,他调用拷贝构造函数的时候,(我们调用函数的时候,第一步先传参,C++的逻辑嘛,传参之前先要传给拷贝构造函数,当拷贝构造函数处理完成之后再传回给调用了的那个函数)那么它就会先把d1的内容传给拷贝构造函数,然后传给拷贝构造函数之后就要进行下一步了,但是当你传给拷贝构造函数之后,你会发现,拷贝后函数又会认为你的这个行为是一个传参的行为,所以他就又会传给拷贝构造函数,就这样一直循环了,死循环了,造成了一个深度的递归

与默认构造函数和析构函数的不同

拷贝构造函数和我们之前学的析构函数和默认构造函数的不同就是当我们不写它的时候,编译器默认生成的拷贝构造函数可以处理内置类型,它会对内置类型进行值拷贝 对自定义类型调用他相应的拷贝。

总结一下

日期类(Date)不需要我们实现拷贝构造,编译器默认生成的就可以直接用了。
但是栈这个类需要我们自己来写一个拷贝构造函数来实现深拷贝,因为编译器默认生成的会出现问题

注意:

//拷贝构造函数 用同类型的对象来初拷贝始化它,所以叫拷贝构造Date(const Date& d){cout << "Date(Date& d)" << endl;_year = d._year;_month = d._month;_day = d._day;}

我们为什么要加一个const?
因为在使用的时候,如果某一天你喝了酒,你把两个变量的位置写反了,这个时候你又没有察觉。那么就会造成一些错误的情况出现。
所以这个时候我们可以在前面加一个const限制一下。
加了const之后,他的权限就变小了,也符合引用的规则

进行引用的时候,权限是可以缩小的,但是是不能放大的

相关文章:

c++ 拷贝构造

我们思考一下这个问题&#xff1a; 观察以下代码&#xff0c;在运行的时候会崩溃 想一想为什么 #include<iostream> using namespace std;//栈类 typedef int DataType; class Stack { public://默认构造&#xff1a;Stack(size_t capacity 3){_array (DataType*)ma…...

MISRA 2012学习笔记(1)-Directives

文章目录 说明Directives2 编译与构建Dir 2.1 3 需求可追溯性Dir 3.1 4 代码设计Dir 4.1Dir 4.2Dir 4.3Dir 4.4Dir 4.5Dir 4.6Dir 4.7Dir 4.8Dir 4.9Dir 4.10Dir 4.11Dir 4.12Dir 4.13 说明 以下等级一般分为三种&#xff0c;建议&#xff0c;必要&#xff0c;强制 建议&#…...

升级node版本后vue2的项目node-sass、sass-loader安装报错(14.x升级到16.x)

node升级到16.x版本后&#xff0c;对应的node-sass需要升级到^6.0.0&#xff0c;此时sass-loader的版本需要升级到10.2.0以上 &#xff0c;具体对应版本规则可参考链接: https://github.com/webpack-contrib/sass-loader/releases?page3 vue2通过vue/cli创建的项目&#xff0…...

深入理解CSS选择器:选择正确的方式掌控样式与布局

文章目录 CSS 概括CSS 选择器元素选择器&#xff08;Element Selector&#xff09;类选择器&#xff08;Class Selector&#xff09;ID 选择器&#xff08;ID Selector&#xff09;通用选择器&#xff08;Universal Selector&#xff09;属性选择器&#xff08;Attribute Selec…...

qt设置控件的风格样式

设置tablewidget ui.tableWidget_MaterialLibrary->setStyleSheet("QTableView {""color:#DCDCDC;""background-color: #444444;""border: 1px solid #242424;""alternate-background-color:#525252;""gridline-co…...

简单易懂的Transformer学习笔记

1. 整体概述 2. Encoder 2.1 Embedding 2.2 位置编码 2.2.1 为什么需要位置编码 2.2.2 位置编码公式 2.2.3 为什么位置编码可行 2.3 注意力机制 2.3.1 基本注意力机制 2.3.2 在Trm中是如何操作的 2.3.3 多头注意力机制 2.4 残差网络 2.5 Batch Normal & Layer Narmal 2.…...

C语言经典小游戏之三子棋(超详解释+源码)

“纵有疾风来&#xff0c;人生不言弃&#xff0c;风乍起&#xff0c;合当奋意向此生。” 今天我们一起来学习一下三子棋小游戏用C语言怎么写出来&#xff1f; 三子棋小游戏 1.游戏规则介绍2.游戏准备3.游戏的实现3.1生成菜单3.2游戏的具体实现3.2.1初始化棋盘3.2.2打印棋盘3.2…...

宝塔Linux面板点击SSL闪退打不开?怎么解决?

宝塔Linux面板点击SSL证书闪退如何解决&#xff1f;旧版本的宝塔Linux面板确实存在这种情况&#xff0c;如何解决&#xff1f;升级你的宝塔Linux面板即可。新手站长分享宝塔面板SSL闪退的解决方法&#xff1a; 宝塔面板点击SSL证书闪退解决方法 问题&#xff1a;宝塔Linux面板…...

Problem: 6953. 判断是否能拆分数组

Problem: 6953. 判断是否能拆分数组 文章目录 思路解题方法复杂度Code 思路 针对题目中的以下目标&#xff0c;可以转换寻求数组中是否存在前后两个元素之和>m的情况&#xff0c;如果存在则返回ture&#xff0c;如果不存在则返回false。能这样转换的原因是&#xff0c;如果…...

MobiSys 2023 | 多用户心跳监测的双重成形声学感知

注1:本文系“无线感知论文速递”系列之一,致力于简洁清晰完整地介绍、解读无线感知领域最新的顶会/顶刊论文(包括但不限于 Nature/Science及其子刊; MobiCom, Sigcom, MobiSys, NSDI, SenSys, Ubicomp; JSAC, 雷达学报 等)。本次介绍的论文是:<<MobiSys’23,Multi-User A…...

Netty:ChannelInitializer添加到ChannelPipeline完成任务以后会自动删除自己

说明 io.netty.channel.ChannelInitializer是一个特殊的ChannelInboundHandler。它的主要作用是向 Channel对应的ChannelPipeline中增加ChannelHandler。执行完ChannelInitializer的initChannel(C ch)函数以后&#xff0c;ChannelInitializer就会从ChannelPipeline自动删除自己…...

【VUE】项目本地开启https访问模式(vite4)

在实际开发中&#xff0c;有时候需要项目以https形式进行页面访问/调试&#xff0c;下面介绍下非vue-cli创建的vue项目如何开启https 环境 vue: ^3.2.47vite: ^4.1.4 根据官方文档&#xff1a;开发服务器选项 | Vite 官方中文文档 ps&#xff1a;首次操作&#xff0c;不要被类…...

【状态估计】一维粒子滤波研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

设计模式-迭代器模式在Java中使用示例

场景 为开发一套销售管理系统&#xff0c;在对该系统进行分析和设计时&#xff0c;发现经常需要对系统中的商品数据、客户数据等进行遍历&#xff0c; 为了复用这些遍历代码&#xff0c;开发人员设计了一个抽象的数据集合类AbstractObjectList&#xff0c;而将存储商品和客户…...

Maven入职学习

一、什么是Maven&#xff1f; 概念&#xff1a; Maven是一种框架。它可以用作依赖管理工具、构建工具。 它可以管理jar包的规模、jar包的来源、jar包之间的依赖关系。 它的用途就是管理规模庞大的jar包&#xff0c;脱离IDE环境执行构建操作。 具体使用&#xff1a; 工作机…...

【多音音频测试信号】具有指定采样率和样本数的多音信号,生成多音信号的相位降低波峰因数研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

LeetCode150道面试经典题-删除有序数组中的重复项(简单)

1.题目 给你一个 升序排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量为 k &#xff0c…...

人大金仓数据库Docker部署

docker 搭建 yum -y install yum-utilsyum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.reposystemctl start docker.servicesystemctl enable docker.servicesystemctl status docker.service 配置Docker cd /etc/docker/ vi da…...

Leetcode-每日一题【剑指 Offer 07. 重建二叉树】

题目 输入某二叉树的前序遍历和中序遍历的结果&#xff0c;请构建该二叉树并返回其根节点。 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 示例 1: Input: preorder [3,9,20,15,7], inorder [9,3,15,20,7]Output: [3,9,20,null,null,15,7] 示例 2: Input: preo…...

Shell编程快速入门

Shell编程快速入门 脚本格式要求 脚本以#!/bin/bash开头脚本需要有可执行权限 脚本的常用执行方式 方式1&#xff1a;输入脚本的绝对路径或相对路径方式2&#xff1a;sh脚本 Shell的变量 Shell变量介绍 Linux Shell中的变量分为系统变量和用户自定义变量 系统变量&#…...

免费高效获取通达信金融数据:MOOTDX量化投资接口终极指南

免费高效获取通达信金融数据&#xff1a;MOOTDX量化投资接口终极指南 【免费下载链接】mootdx 通达信数据读取的一个简便使用封装 项目地址: https://gitcode.com/GitHub_Trending/mo/mootdx 想要快速获取A股市场数据却苦于高昂的API费用&#xff1f;MOOTDX是你的完美解…...

第08章 FastAPI 与 SSE 流式 RAG 后端

第08章 FastAPI 与 SSE 流式 RAG 后端 到目前为止&#xff0c;知识库、检索工具、MCP 客户端都已经就绪&#xff0c;但仍缺少一个面向最终用户的入口。本章用 FastAPI 把整条 RAG 链路串起来&#xff1a;接收前端发来的自然语言问题&#xff0c;调用 MCP 工具检索相关工单&…...

无线渗透测试框架Airecon:自动化工具链整合与实战应用

1. 项目概述与核心价值最近在整理自己的渗透测试工具箱时&#xff0c;又翻出了pikpikcu/airecon这个老伙计。说实话&#xff0c;在无线安全评估这个细分领域里&#xff0c;它可能不是名气最响的那个&#xff0c;但绝对是我个人在内部网络渗透和红队演练中最顺手、最高效的“组合…...

Wand-Enhancer:免费解锁WeMod专业版功能的终极本地增强工具

Wand-Enhancer&#xff1a;免费解锁WeMod专业版功能的终极本地增强工具 【免费下载链接】Wand-Enhancer Advanced UX and interoperability extension for Wand (WeMod) app 项目地址: https://gitcode.com/gh_mirrors/we/Wand-Enhancer 还在为WeMod专业版的高昂订阅费用…...

Arm Cortex-X2/X3架构解析与性能优化实践

1. Arm Cortex-X2/X3集群架构概述在Armv9架构的高性能计算领域&#xff0c;Cortex-X2和X3代表了当前最先进的CPU设计理念。作为DynamIQ共享单元(DSU)的核心组件&#xff0c;它们通过可配置的缓存层次结构和智能一致性协议&#xff0c;为现代异构计算提供了灵活的解决方案。1.1 …...

qmcdump终极指南:三步解锁QQ音乐加密音频文件

qmcdump终极指南&#xff1a;三步解锁QQ音乐加密音频文件 【免费下载链接】qmcdump 一个简单的QQ音乐解码&#xff08;qmcflac/qmc0/qmc3 转 flac/mp3&#xff09;&#xff0c;仅为个人学习参考用。 项目地址: https://gitcode.com/gh_mirrors/qm/qmcdump 还在为QQ音乐下…...

MySQL 索引底层 B+ 树原理

聊 MySQL 索引&#xff0c;不讲 B 树&#xff0c;那就是在耍流氓。 大家好&#xff0c;我是乱码字符。今天咱们深入聊聊 MySQL 索引的底层数据结构——B 树。这篇文章能让你彻底搞明白&#xff0c;为什么有时候明明加了索引&#xff0c;查询却还是慢成狗。 先说说为什么要用树结…...

像素艺术家紧急预警:Midjourney即将关闭--tile参数兼容性(倒计时14天),现在必须掌握的3种替代渲染方案

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;像素艺术家紧急预警&#xff1a;Midjourney即将关闭--tile参数兼容性&#xff08;倒计时14天&#xff09; Midjourney v6.5 已正式宣布将于 14 天后终止对 --tile 参数的原生支持&#xff0c;此举将直…...

人性最残忍的真相是:你越不把自己当回事,别人就越不把你当回事

那个总给别人买贵东西的人,最后都怎么样了? 目录 那个总给别人买贵东西的人,最后都怎么样了? 我们为什么会忍不住过度付出? 真正的爱,从来都不是单方面的牺牲 爱自己,是所有健康关系的前提 昨天刷到一句话,瞬间戳中了我:“永远不要拿自己辛苦钱,去给别人买自己都舍不…...

Claude-Code-KnowCraft:轻量级代码知识库构建与智能问答实践

1. 项目概述与核心价值最近在跟几个做AI应用开发的朋友聊天&#xff0c;大家普遍有个痛点&#xff1a;想把Claude这类大语言模型&#xff08;LLM&#xff09;的能力深度集成到自己的代码库分析工具里&#xff0c;但发现现有的方案要么太重&#xff0c;要么太浅。太重的是指那些…...