news 2026/8/4 5:16:17

【C++】022、深拷贝浅拷贝

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【C++】022、深拷贝浅拷贝

一、深拷贝&浅拷贝

深拷贝与浅拷贝的根本区别,不在于复制了多少字节,在于拷贝后,两个对象是否共享了同一个底层资源

  • 浅拷贝:仅仅逐字节复制对象本身的内存布局,两个对象中的指针成员指向同一块动态内存。

  • 深拷贝:递归复制指针所指向的全部底层数据,为副本独立分配一块新的动态内存。

二、代码解析与示意图

1、浅拷贝,编译器默认行为

原始对象 s1 (栈) 堆内存 (0x1000) ┌─────────────┐ ┌─────────────┐ │ char* m_ptr │──────│ H E L L O \0│ │ int m_len=5 │ └─────────────┘ └─────────────┘ 拷贝对象 s2 (栈) ┌─────────────┐ │ char* m_ptr │──────(指向同一块 0x1000) ❌ 共享了! │ int m_len=5 │ └─────────────┘

2、深拷贝,手动处理

原始对象 s1 (栈) 堆内存 (0x1000) ┌─────────────┐ ┌─────────────┐ │ char* m_ptr │──────│ H E L L O \0│ │ int m_len=5 │ └─────────────┘ └─────────────┘ 拷贝对象 s2 (栈) 堆内存 (0x2000) ✅ 独立新家! ┌─────────────┐ ┌─────────────┐ │ char* m_ptr │──────│ H E L L O \0│ │ int m_len=5 │ └─────────────┘ └─────────────┘

3、代码演示

#include <cstring> #include <iostream> class MyString { private: char* m_data; // 指向堆内存的指针 size_t m_len; public: // ---------- 构造函数 ---------- MyString(const char* str = "") : m_len(strlen(str)), m_data(new char[m_len + 1]) { strcpy(m_data, str); std::cout << "构造: " << m_data << std::endl; } // ---------- 析构函数 ---------- ~MyString() { delete[] m_data; // 释放堆内存 std::cout << "析构: 释放内存" << std::endl; } // ========================================== // ❌ 浅拷贝(编译器默认生成,如果不禁用会出大问题) // ========================================== // 默认拷贝构造:MyString(const MyString& other) // 默认拷贝赋值:MyString& operator=(const MyString& other) // 它们会执行:m_data = other.m_data; (逐字节复制指针值) // 后果:两个对象指向同一块内存,析构时双重释放(Double Free)-> 崩溃! // ========================================== // ✅ 深拷贝(必须手动实现) // ========================================== // 1. 拷贝构造函数(深拷贝) MyString(const MyString& other) : m_len(other.m_len), m_data(new char[m_len + 1]) { strcpy(m_data, other.m_data); // 复制数据到新内存 std::cout << "深拷贝构造: " << m_data << std::endl; } // 2. 拷贝赋值运算符(深拷贝 + 自我赋值检测) MyString& operator=(const MyString& other) { std::cout << "深拷贝赋值: " << other.m_data << std::endl; if (this == &other) { // 防止自我赋值:s = s; return *this; } // 步骤1:释放旧资源 delete[] m_data; // 步骤2:分配新内存并复制数据 m_len = other.m_len; m_data = new char[m_len + 1]; strcpy(m_data, other.m_data); return *this; } // 获取数据(打印用) const char* c_str() const { return m_data; } }; // ========== 测试代码 ========== int main() { MyString s1("Hello"); MyString s2(s1); // 调用深拷贝构造(独立内存) MyString s3("World"); s3 = s1; // 调用深拷贝赋值(s3 释放旧内存,申请新内存) std::cout << "s1: " << s1.c_str() << std::endl; std::cout << "s2: " << s2.c_str() << std::endl; std::cout << "s3: " << s3.c_str() << std::endl; return 0; // 三个对象析构,各自释放各自的内存,安全! }

三、工程实战原则

1、三/五法则:

  • 如果一个类需要自定义析构函数释放资源,那么一定需要自定义拷贝构造函数和拷贝赋值运算符,以及C11后的移动构造和移动赋值

  • 反之,如果不需要析构函数,就不要自定义拷贝操作,直接让编译器生成默认的浅拷贝。

2、在业务代码中,使用string替换char*,用vector替换动态数组

  • 因为他们内部已实现了深拷贝。

四、C11中的移动语义

  • C++中的移动语义既不是深拷贝,也不是浅拷贝,只是一种资源窃取

解析:

  • 浅拷贝会导致两个对象共享资源,存在重复释放资源危险

  • 深拷贝会复制一份数据(昂贵)

  • 移动是把源对象的指针直接置空(nullptr),并把指针值偷给目标对象,移动后的源对象处于有效但未指定的状态,他的析构函数不会再释放资源。

移动语义完美的解决了深拷贝的性能开销问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/4 5:14:56

STM32F407 USB Custom HID免驱通信:从CubeMX配置到Python上位机实战

1. 项目缘起&#xff1a;为什么是STM32F407的USB Custom HID&#xff1f;最近在做一个需要和电脑进行双向数据交互的小设备&#xff0c;核心需求是&#xff1a;设备&#xff08;下位机&#xff09;能实时上报一些传感器数据&#xff0c;同时电脑&#xff08;上位机&#xff09;…

作者头像 李华
网站建设 2026/8/4 5:11:29

基于MATLAB SISO Tool的PID控制器交互式设计与仿真实践

1. 项目概述&#xff1a;从理论到实践的PID控制器设计之旅在自动化、机器人、航空航天乃至化工过程控制等众多工程领域&#xff0c;控制系统的设计是确保设备或过程稳定、精确、高效运行的核心。而PID控制器&#xff0c;作为控制理论中应用最广泛、最经典的控制器结构&#xff…

作者头像 李华
网站建设 2026/8/4 5:09:27

C++代码冗余消除与性能优化实战

1. 为什么C项目需要消除代码冗余&#xff1f;在维护大型C项目时&#xff0c;代码冗余就像房间里堆积的杂物——初期看似无害&#xff0c;但随着时间推移会严重影响开发效率。我经历过一个3年历史的交易系统项目&#xff0c;由于早期缺乏规范&#xff0c;相同功能的订单处理逻辑…

作者头像 李华
网站建设 2026/8/4 5:08:53

医学大模型深度研究报告(2026年8月版第二部分)

3.4 多模态对齐 3.4.1 MedGemma 的公开配方(目前最完整) 【B】: 编码器:SigLIP-400M;输入 896896、像素归一化到 [−1,1];发现许多医学视觉任务在 448448 已足够,故 MedSigLIP 单独以 448 发布,与 896 共享同一套权重,仅下采样位置嵌入——这是很实用的分辨率适配技…

作者头像 李华
网站建设 2026/8/4 5:07:23

Java实现智能集群仿真:Boids模型与并发优化实践

1. 项目背景与核心目标这个Java仿真智能集群项目源于我在分布式系统课程中的一次实践需求。当时教授布置了一个开放性课题&#xff1a;用任意编程语言模拟自然界中的群体智能行为。我选择了Java作为实现语言&#xff0c;一方面因为这是我最熟悉的编程语言&#xff0c;另一方面J…

作者头像 李华
网站建设 2026/8/4 5:05:07

【2026热端攻防系列 11/12】前端AI风控攻防实战:验证码缺陷、人机验证绕过、智能爬虫对抗与企业智能风控加固方案

标签&#xff1a;#Web安全 #前端安全 #热端攻防 #AI风控 #人机验证 #验证码安全 #反爬虫 #智能对抗 #2026安全热点&#x1f512; 安全合规声明&#xff1a;本文内容仅用于网络安全合规学习、企业风控体系建设、安全攻防复盘与防御研究。全文仅讲解风控漏洞成因、验证机制缺陷、…

作者头像 李华