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

C++拷贝构造函数详解:从浅拷贝到深拷贝

什么是拷贝构造函数?

拷贝构造函数是C++中的一种特殊构造函数,用于创建一个新对象作为现有对象的副本。当我们使用一个对象来初始化同类型的另一个对象时,拷贝构造函数就会被调用。

基本语法

class MyClass {
public:// 拷贝构造函数MyClass(const MyClass& other) {// 拷贝操作}
};

何时调用拷贝构造函数?

拷贝构造函数在以下情况下被调用:

  1. 对象初始化

    MyClass obj1;
    MyClass obj2 = obj1; // 拷贝构造函数被调用
    MyClass obj3(obj1);  // 拷贝构造函数被调用
    
  2. 函数参数传递(按值传递):

    void doSomething(MyClass obj) {// 函数体
    }MyClass myObj;
    doSomething(myObj); // 拷贝构造函数被调用
    
  3. 函数返回值(按值返回):

    MyClass createObject() {MyClass obj;return obj; // 可能调用拷贝构造函数(取决于编译器优化)
    }
    

默认拷贝构造函数的问题:浅拷贝

如果你没有自定义拷贝构造函数,编译器会自动生成一个默认的拷贝构造函数。这个默认实现执行浅拷贝(成员逐一复制),对于简单类型没问题,但对于指针成员会导致问题:

class ShallowCopy {
private:int* data;int size;
public:ShallowCopy(int sz) : size(sz) {data = new int[size];}// 默认拷贝构造函数执行浅拷贝:// data = other.data; (复制指针值,而不是指向的内容)// size = other.size;~ShallowCopy() {delete[] data;}
};

使用这个类会导致双重释放问题:

ShallowCopy obj1(10);
ShallowCopy obj2 = obj1; // 浅拷贝:两个对象的data指向同一内存
// obj1和obj2析构时都会尝试释放同一块内存 → 崩溃!

解决方案:深拷贝

为了解决浅拷贝的问题,我们需要自定义拷贝构造函数来实现深拷贝

class DeepCopy {
private:int* data;int size;
public:DeepCopy(int sz) : size(sz) {data = new int[size];}// 自定义拷贝构造函数(深拷贝)DeepCopy(const DeepCopy& other) : size(other.size) {data = new int[size];for (int i = 0; i < size; ++i) {data[i] = other.data[i]; // 复制内容,而不是指针}}~DeepCopy() {delete[] data;}
};

完整的示例代码

#include <iostream>
#include <cstring>class String {
private:char* str;int length;public:// 普通构造函数String(const char* s = "") {length = std::strlen(s);str = new char[length + 1];std::strcpy(str, s);}// 拷贝构造函数(深拷贝)String(const String& other) : length(other.length) {str = new char[length + 1];std::strcpy(str, other.str);std::cout << "拷贝构造函数被调用" << std::endl;}// 析构函数~String() {delete[] str;}// 显示字符串void display() const {std::cout << str << std::endl;}// 修改字符串void update(const char* s) {delete[] str;length = std::strlen(s);str = new char[length + 1];std::strcpy(str, s);}
};int main() {String s1("Hello");String s2 = s1; // 拷贝构造函数被调用std::cout << "s1: ";s1.display();std::cout << "s2: ";s2.display();s1.update("World"); // 修改s1,不影响s2std::cout << "修改后:" << std::endl;std::cout << "s1: ";s1.display();std::cout << "s2: ";s2.display();return 0;
}

拷贝构造函数与赋值运算符的区别

初学者常常混淆拷贝构造函数和赋值运算符,它们的区别在于:

  • 拷贝构造函数:创建新对象时使用
  • 赋值运算符:已存在的对象被赋予新值时使用
MyClass obj1;
MyClass obj2 = obj1; // 拷贝构造函数
MyClass obj3;
obj3 = obj1;         // 赋值运算符

禁止拷贝

有时候我们想禁止对象的拷贝行为,C++11之前可以通过将拷贝构造函数声明为private来实现,C++11之后可以使用delete关键字:

class NonCopyable {
public:NonCopyable() = default;// 禁止拷贝NonCopyable(const NonCopyable&) = delete;NonCopyable& operator=(const NonCopyable&) = delete;
};

最佳实践

  1. 三分法则:如果你需要自定义析构函数、拷贝构造函数或拷贝赋值运算符中的任何一个,你可能需要自定义所有这三个。

  2. 考虑使用智能指针:现代C++中,使用std::unique_ptrstd::shared_ptr可以避免许多手动内存管理的问题。

  3. 优先使用const引用传递对象:避免不必要的拷贝,提高性能。

  4. 考虑移动语义:C++11引入了移动构造函数和移动赋值运算符,对于管理资源的类,实现移动语义可以显著提高性能。

总结

拷贝构造函数是C++中管理对象复制行为的重要工具。理解浅拷贝和深拷贝的区别对于编写正确、安全的C++代码至关重要。对于包含动态分配资源的类,几乎总是需要自定义拷贝构造函数来实现深拷贝,避免潜在的内存问题和未定义行为。

在现代C++开发中,随着智能指针和移动语义的引入,我们需要手动实现拷贝构造函数的情况减少了,但理解其原理仍然非常重要。

相关文章:

C++拷贝构造函数详解:从浅拷贝到深拷贝

什么是拷贝构造函数? 拷贝构造函数是C++中的一种特殊构造函数,用于创建一个新对象作为现有对象的副本。当我们使用一个对象来初始化同类型的另一个对象时,拷贝构造函数就会被调用。 基本语法 class MyClass { public:// 拷贝构造函数MyClass(const MyClass& other) {// …...

K8S探针

https://blog.csdn.net/weixin_28820113/article/details/148380309 HTTP探测实战(最常用) 向容器发送 HTTP 请求,若返回状态码为 200-399,则表示检查成功[root@master ~/probe]# cat readiness.yaml kind: Pod apiVersion: v1 metadata:name: nginxlabels:app: nginx spec…...

模拟赛

波波牛的惩罚 我们先处理出每个数可能影响的数,可以用链式前向星或 vector 我们维护一个队列,在最开始的时候放入最小值。 每次取出一个数,然后遍历所有可以影响的数,并把影响成功的数放进队列。 在最后判一下是否相同即可。 复杂度 \(O(n)\)。点击展开代码 #include<bi…...

bug1

9.16 修复报错字体大小bug 补充日志 TeXmacs/progs/debug/debug-widgets.scm 修改build-message 为以下 (define (build-message m)(let* ((k (tm->stree (tm-ref m 0)))(s (utf8->cork (tm->stree (tm-ref m 1))))(t (tm->stree (tm-ref m 2))))(cond ((string-e…...

C#第十二天 025

父类如果只有有参构造器,子类会默认去调用父类的无参构造器,如果子类要有无参构造器需要这样 子类构造器():base(参数)你的理解​​完全正确​​!当父类​​只有有参构造器​​时,子类必须​​显式调用父类的有参构造器​​,否则会编译错误。 类成员的访问级别不能超…...

选择语句的机器级表示

无条件转移指令--jmp 格式: jmp <地址> #pc无条件跳转到<地址> <地址>可以由常数直接给出:jmp 5 <地址>可以来自于寄存器:jmp eax <地址>可以来自于主存 :jmp [999] <地址>可以用“标号”锚定:jmp NEXT 100 mov eax,7 104 mov ebx,6 …...

pip常用命令

好的,这是 Python 包管理工具 pip 的常用命令大全,涵盖了从安装、升级、查询到问题排查的所有核心操作。一、核心命令:安装与卸载命令 描述 示例pip install <package_name> 安装最新版本的包 pip install requestspip install <package_name>==<version>…...

Nginx auth_request 模块使用

Nginx auth_request 模块使用笔记 📌 模块概述 nginx-auth-request-module(官方名:http_auth_request_module)用于在请求处理前向外部服务进行认证验证。 🔧 安装与启用 # 编译时添加模块 ./configure --add-module=/path/to/nginx-auth-request-module# 检查是否已安装…...

用nssm将minio和srs注册成服务

首先,要注意一个关键问题,不要在nssm中直接调用batNSSM 与 Bat 文件的问题:当NSSM启动一个批处理文件(.bat)时,它实际启动的是cmd.exe进程,而批处理中的命令(如minio.exe)则是其子进程。NSSM会监视cmd.exe的状态。一旦批处理中的命令执行完毕,cmd.exe进程就会退出,N…...

Mac上的Markdown学习

Markdown学习 标题 一个#+空格表示一级标题 两个#+空格表示二级标题 ……同理,几个#+空格表示几级标题 字体 粗体 Hello World 前后两个*表示粗体 斜体 Hello World 前后一个*表示斜体 斜体加粗 Hello World 前后三个*表示斜体加粗 删除线 Hello world 前后两个英文字符~表示删…...

ubuntu 18.04安装mysql8.4.5

环境Os:ubuntu 18.04 desktop桌面版mysql:8.4.5 glibc2.17 查看操作系统信息root@db:/# ldd --version ldd (Ubuntu GLIBC 2.27-3ubuntu1) 2.27 Copyright (C) 2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is…...

Radxa E20C 安装 OpenWrt

背景 今天浏览 Radxa E20C 官方文档中无意中发现设备可以安装 OpenWrt,如下图:Radxa E20C 官方文档安装 OpenWrt参考链接: E20C->上手指南->安装系统->安装系统到EMMC->Windows主机创建目录 01-DriverAssistant v5.0, 下载 DriverAssistant v5.0 ,并解压和安装…...

第三篇:配置浏览器

111111车到山前必有路,学到苦海甘甜来。只有知识和阅历对的起自己的年龄,美好的生活才不会欺骗自己!...

第二篇:playwright初步解析

以下是一个完整的测试用例,模拟用户登录功能: 脚本示例:from playwright.sync_api import sync_playwrightdef test_login(): with sync_playwright() as p: # 启动浏览器 browser = p.chromium.launch(headless=True) page = browser.new_page()# 打开…...

高性能计算-TensorCore-hgemm

1. TensorCore 简介:硬件层面支持半精度浮点矩阵乘法,与昇腾NPU的 cube 核类似,最小只能计算规定尺寸的矩阵乘法。 wmma API 封装在 nvcuda 命名空间2. naive :一个block 1 个warp,wmmaTile 16*16点击查看代码 //naive 一个block 一个warp,一个线程处理一个数据 template …...

《ESP32-S3使用指南—IDF版 V1.6》第三十八章 SPIFFS实验

第三十八章 SPIFFS实验 1)实验平台:正点原子DNESP32S3开发板 2)章节摘自【正点原子】ESP32-S3使用指南—IDF版 V1.6 3)购买链接:https://detail.tmall.com/item.htm?&id=768499342659 4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/esp32/…...

技术交流社区基础防诈指南

技术交流社区基础防诈指南技术交流社区基础防诈指南 若已确认被骗或发现违法内容,请立即通过以下渠道举报:公安部网络违法犯罪举报网站:12321.cn (网络不良信息) 国家反诈中心:拨打 110 或通过官方APP举报 (注意:报警时务必索要《受案回执》) 中央网信办违法和不良信息举报…...

神秘题

Trick排列置换题,考虑转化乘环上移动问题。题目 精灵之环 假设知道排列 \(p\)。 那么把这个排列 \(p\) 的环连出来,环上点的编号是排列的下标,点的值是编号对应的值。 就比如排列 4 1 2 3 的环为: val: 4 1 2 3 4 id : 1->2->3->4->1...可以发现把这些环上…...

技术群高级防骗指南

技术群高级防骗指南技术群高级防骗指南 怎么骗的 怎么防 被骗会怎么样 怎么骗的 1.资源储备与身份伪装: 1.盗盗取大量高等级账号并使用,给人友好可信的虚假印象2.养 ​ 骗子可能会花时间养这些盗来的号, 参与正常讨论,发一些专业的言论, 或者爆出自己是某某名牌大学来的 / 某…...

集训游记

前言 关于我 2025-9-16 开始写游击这件事情,其实已经考了 10 多次了,感觉前几次还好,后面被削弱了/kk,肯定是感冒debuff的问题,目前是能碾压ysh和lh的部分时候可以干掉xch,别的没咋关注.exe 2025-9-16 上午考试,比赛题目居然叫做 fish、oblivious、array、digit...

SQL Server 中的 STUFF 函数与FOR XML PATH详解 - 实践

SQL Server 中的 STUFF 函数与FOR XML PATH详解 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", mono…...

2025/9/16 总结

A 用时:2h 预期:0pts 实际:0pts 考试是没有想到可以考虑 \(p_k\) 的置换环,思考许久没有思路。 然后打表找构造方法没有找出来心态就炸了,导致后面基本没有写暴力,直接垫底了。 总结:对于这种排列问题,可以考虑置换处理。考试心态不要炸,即使不会做也要打暴力。B 用时…...

Linux备份数据

linux备份常用技术一、备份数据库 1、准备一份备份命令sh文件,比如将其存放在/opt/db_bak中,命名为bak_mysql.sh#!/bin/bash # MySQL备份配置 MYSQL_USER="root" MYSQL_PASSWORD="root" MYSQL_HOST="10.10.10.10" MYSQL_PORT="3306"…...

np.argmax

argmax 是 NumPy 和许多其他科学计算库(如 PyTorch、TensorFlow)中的一个非常常用的函数,它的作用是返回数组中最大值的索引。 简单来说,argmax 告诉你最大值在哪里,而不是最大值是多少。 argmax 的基本用法 np.argmax(a, axis=None, out=None)a: 你要查找最大值索引的数组…...

TQ322数字PIR使用笔记

TQ322 数字PIR特性: 双元单通数字输出热释电红外传感器我使用中断读取的方式即时获取数字PIR传感器内最新的数据具体时序如下: 单片机IO 模拟时序程序如下: (代码中NOP数量根据单片机主频和型号自行调整)/*-------------------------------------------------* 函数名:D…...

使用Apache做web服务器时无法断点续传的怎么办?

Apache 作为 Web 服务器时,如果无法实现 断点续传 功能,通常是因为配置问题或文件系统的限制。断点续传是指用户在中断下载后,可以从上次中断的地方继续下载,而不是重新开始。以下是可能的原因分析和解决方法。1. 什么是断点续传?断点续传(HTTP Range 请求):由客户端发…...

Rust使用rbatis

toml rbs = { version = "4.6"} rbatis = { version = "4.6"} #drivers rbdc-mysql = { version = "4.6" } # 其他依赖 serde = { version = "1", features = ["derive"] } serde_json = "1.0" tokio = { version…...

2025ICPC网络赛第一场(A,B,C,D,G,I,M)

A. Who Can Win https://qoj.ac/contest/2513/problem/14301 思路 按题意模拟,统计第 \(239min\) 时成绩最好的队伍,记为冠军队伍,从 \(240min\) 开始到比赛结束的所有队伍都假设提交通过,实时计算成绩,一旦超过 \(239min\) 前的成绩最好队伍同样记作冠军。 细节: 1.输出…...

Google Maps

Google Maps...

【TES600G】基于JFM7K325T FPGA+FT-M6678 DSP的全国产化信号处理平台

​ 产品概述 TES600G是一款基于FPGA+DSP协同处理架构的通用高性能实时信号处理平台,该平台采用1片国防科大的银河飞腾多核浮点/定点DSP FT-M6678作为主处理单元,采用1片复旦微的Kintex-7系列FPGA JFM7K325T16作为协处理单元,具有1个FMC子卡接口,具有4路SFP+万兆光纤接口,…...

KMS激活Windows系统(win10)

在开始菜单上右键,选择 Windows PowerShell(管理员),依次输入以下命令即可激活成功 slmgr /ipk NPPR9-FWDCX-D2C8J-H872K-2YT43 slmgr /skms kms.03k.org slmgr /ato 1、安装产品密钥,不同的操作系统激活码不一样,网上搜索下有很多,这些激活码不能在线直接激活,但可以通过…...

基于python3的http文件服务器

前言跨环境或者跨跳板机传输文件很麻烦,比如从windows系统跨跳板机传输文件到linux系统,这时候scp就不适用了。 比较简单的方式是,从windows系统开一个http文件服务,然后从linux系统直接使用http链接下载。 如果是自己的环境,直接使用python3 -m http.server --bind 0.0.0…...

大阪府

大阪府名称大阪城 心斋桥 道顿崛 海游馆 通天阁 四天王寺 环球影城 万博纪念公园 中之岛公园 天保山摩天轮...

sql server2008大批量插入数据

谨慎使用update 最好对应字段 直接使用insertDECLARE @pageIndex INTDECLARE @pageSize INTDECLARE @TotalpageIndex INTdeclare @rows as int SET @pageIndex = 1SET @pageSize = 10000set @TotalpageIndex=((select top 1 ID from [NewWeBusiness_PJM].[dbo].[Scale] order …...

【Office 2010】经典办公套件Office 2010——保姆级详细图文下载安装教程 - 详解

【Office 2010】经典办公套件Office 2010——保姆级详细图文下载安装教程 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "…...

Eth-Trunk实验

...

HCIP—Eth-Trunk

...

一个还不错的,简单的,前端vue2后台框架

https://gitee.com/e4glet/vue-cli4-framwork相信坚持的力量,日复一日的习惯....

P4099 [HEOI2013] SAO

题意:给定一棵有 \(n\) 个点(\(n \le 1000\))的树,每条边 \((u, v)\) 有参数 \(c\) 表明 \(u\) 和 \(v\) 谁必须排在前面,求满足所有边条件的排列种数。思路:采用容斥原理解决。先以 \(1\) 为根,将所有 \(c = 1\) 的边看作无限制,求方案数,再通过容斥调整。可在树形DP…...

Linux chronyd 时间同步服务器,命令

Linux chronyd 时间同步服务器,命令chronyd 是 Linux 系统中常用的时间同步服务工具,以下是其常用命令:启动 / 停止 / 重启服务:# 启动服务 sudo systemctl start chronyd # 停止服务 sudo systemctl stop chronyd # 重启服务 sudo systemctl restart chronyd # 查看服务状…...

2025暑假集训总结lh

暑假进行了一个月的集训,也刷了不少题,参加了几场萌新赛。让我看出来我目前最大的问题:基础不太牢固。 以前学习c语言,从来没有看过具体的课程,从来都是用到什么就搜什么来学习,导致没有具体的框架在脑子里。 不少题,大致思路我能看出来,也大概知道要用哪些板子,但是一…...

ET框架的 阻止 ddos 设计,软路由

https://et-framework.cn/d/17ET7 软路由 ET7分支已经添加软路由功能~早期分享 最近在做防攻击设计,今天终于完成并且实现了,这里分享给大家,特别是搞棋牌的项目,还有小公司没法通过法律手段来防止别人攻击。特别有用处。因为高防实在太贵,用不起。 设计思路如下:需要有很…...

Serena 最佳实践方案

1. 全局安装 Serena 你需要用 包名 serena-agent 来安装,但安装完后命令行工具叫 serena: uv tool install --from git+https://github.com/oraios/serena serena-agent安装成功后,全局会有一个可执行命令: serena --help后续操作 升级: uv tool upgrade serena-agent卸载…...

C++ 零散记录:条件编译与 if constexpr 的区别

核心区别 条件编译发生在预处理期,由预处理器根据条件关掉代码片段,即不让这些代码到达编译期。 if constexpr:发生在编译期,由编译器在编译期确定要执行的分支。 其他所有的区别都是此核心区别的衍生。 用法的区别 能放的位置 条件编译几乎在哪都行。 if constexpr 只能在…...

ubuntu 22.04安装mysql8.0.41(glibc2.17)

环境Os:ubuntu 22.04 desktop桌面版mysql:mysql:8.0.41 glibc2.17查看操作系统信息root@db:/soft# ldd --version ldd (Ubuntu GLIBC 2.35-0ubuntu3) 2.35 Copyright (C) 2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. …...

cURL调试功能磁盘空间耗尽导致拒绝服务漏洞分析

本文详细分析了cURL工具在使用--trace或--trace-ascii选项时存在的磁盘空间耗尽漏洞,攻击者可通过发送大量数据使日志文件无限增长,导致系统拒绝服务,并提供了修复方案。报告 #3250490 - 磁盘空间耗尽导致拒绝服务(DoS) 描述 当使用--trace或--trace-ascii选项处理大量数据时…...

mysql常用函数,数据处理效率提升实战指南

还在为SQL查询效率低下而烦恼吗?MySQL内置的强大函数库能让你事半功倍!无论是字符串处理、日期计算还是数值运算,熟练使用这些函数能极大简化开发工作。本文将全面解析MySQL最实用的内置函数,助你轻松应对各种数据处理需求。 字符串处理函数的妙用 在处理用户输入、日志分析…...

Tita 一体化管理:赋能互联网企业产品迭代全流程

在互联网行业,产品迭代速度直接决定企业的市场竞争力。然而,多数互联网企业在产品从需求提出到最终上线的全流程中,常面临需求混乱、开发低效、上线失控等问题。Tita 以一体化管理思维,打通产品迭代的全链路,让每一次版本更新都精准、高效、可控。 一、互联网企业产品迭代…...

【2025-09-15】动起来了

20:00仅仅通过改变自己,我们就能改变我们的整个人生和身边人的态度。——鲁道夫德雷克斯今天打算下班在园区投投篮,缓解一下职业病问题。临下班前的一个多小时,突然下起了大雨。那在还要想想,换种运动方式。我的车后备箱有几种运动装备,例如跑步、篮球和游泳。下雨天最好的…...

二叉树的层次遍历

前言 代码 非递归,使用size记录我们到第几层了,每次存入一层的node只有遍历完了才进入下一次循环,queue为空了就结束 代码: class Solution { public:vector<vector<int>> levelOrder(TreeNode* root) {queue<TreeNode*> que;if (root != NULL) que.push…...