0

0

c++如何实现深拷贝与浅拷贝_c++拷贝构造函数技巧【核心】

裘德小鎮的故事

裘德小鎮的故事

发布时间:2026-03-15 21:22:02

|

594人浏览过

|

来源于php中文网

原创

浅拷贝是C++默认行为,仅复制指针地址而非内容,导致双删、野指针等问题;含裸指针或动态资源的类必须手动实现深拷贝:分配新内存→复制数据→更新指针。

c++如何实现深拷贝与浅拷贝_c++拷贝构造函数技巧【核心】

浅拷贝就是默认的,但多数时候它会出问题

当你没写拷贝构造函数时,C++ 会自动生成一个——它逐字节复制对象内存,对指针成员只复制地址,不复制指向的内容。这意味着两个对象的指针变量指向同一块堆内存。一旦其中一个析构时 delete 了这块内存,另一个再访问就是野指针;若都试图 delete,直接触发 double free 错误。

常见错误现象:double free or corruptionsegmentation fault、程序在析构阶段崩溃,且只在对象被拷贝(如传值返回、容器插入)后才出现。

  • 只要类里有裸指针(int*char* 等)、或管理了动态资源(文件句柄、socket、GPU buffer),就必须自己写拷贝构造函数
  • std::stringstd::vector 这类标准容器内部已实现深拷贝,它们的成员不用额外处理
  • 编译器不会警告你“你该写深拷贝”,它只安静地给你一个危险的默认行为

深拷贝必须手动分配新内存并复制内容

核心动作就三步:申请新内存 → 复制原数据 → 更新指针成员。别漏掉任何一步,尤其不能只 newmemcpy 或赋值。

假设有个类管理一个动态数组:

立即学习C++免费学习笔记(深入)”;

class Buffer {
    int* data_;
    size_t size_;
public:
    Buffer(const Buffer& other) : size_(other.size_) {
        data_ = new int[size_];           // ① 分配新内存
        for (size_t i = 0; i < size_; ++i) {
            data_[i] = other.data_[i];    // ② 逐元素复制(不是 memcpy!除非确定 POD)
        }
    }
};
  • 如果用 memcpy(data_, other.data_, size_ * sizeof(int)),对 int 没问题;但对含虚函数、非 POD 类型(比如含 std::string 的结构体),必须用循环或 std::copy
  • 别在拷贝构造函数里调用 operator= —— 它依赖已构造完成的对象,而此时当前对象还没构造完
  • 记得同步更新所有相关成员:比如 size_capacity_、引用计数等,漏掉一个就可能造成越界或逻辑错乱

拷贝构造函数和 operator= 必须一起改,否则行为不一致

只改拷贝构造函数,不改赋值运算符,会导致“同一个类,两种拷贝逻辑”:初始化时深拷,赋值时却浅拷——这是最隐蔽的坑之一。

标小智
标小智

智能LOGO设计生成器

下载

典型错误场景:把对象先声明,再用 = 赋值;或者 vector 扩容时触发移动/拷贝混合操作。

  • 赋值运算符要先检查自赋值:if (this == &other) return *this;,否则 delete data_ 后再读 other.data_ 就崩了
  • 赋值时要先释放旧资源,再分配新资源,顺序反了会内存泄漏
  • C++11 后推荐用“拷贝-交换”惯用法(copy-and-swap),能自动处理自赋值和异常安全,但要注意临时对象开销

现代 C++ 更推荐用 RAII 和智能指针绕过手动深拷贝

如果你发现自己反复在写深拷贝逻辑,大概率是设计上可以优化:把资源管理从裸指针移到 std::unique_ptrstd::shared_ptr,很多问题就消失了。

例如:

class Buffer {
    std::unique_ptr<int[]> data_;
    size_t size_;
public:
    Buffer(const Buffer& other) : size_(other.size_), 
                                  data_(std::make_unique<int[]>(other.size_)) {
        std::copy(other.data_.get(), other.data_.get() + size_, data_.get());
    }
};
  • std::unique_ptr 的拷贝构造默认是删除的(禁用),所以你仍需手动实现——但它帮你管好了 delete,不会忘
  • std::shared_ptr 拷贝是共享引用计数,本质是浅拷贝语义,但行为安全;适合读多写少、需共享所有权的场景
  • RAII 不是银弹:如果业务逻辑确实要求物理隔离(比如两个 Buffer 必须互不影响),那深拷贝仍是唯一选择,只是实现更可靠了

真正容易被忽略的是:深拷贝成本本身。一次拷贝几百 MB 的图像数据?要考虑是否真需要——有时传 const Buffer& 或用 move 语义更合理。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1051

2023.08.02

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1570

2023.10.24

Go语言中的运算符有哪些
Go语言中的运算符有哪些

Go语言中的运算符有:1、加法运算符;2、减法运算符;3、乘法运算符;4、除法运算符;5、取余运算符;6、比较运算符;7、位运算符;8、按位与运算符;9、按位或运算符;10、按位异或运算符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

241

2024.02.23

php三元运算符用法
php三元运算符用法

本专题整合了php三元运算符相关教程,阅读专题下面的文章了解更多详细内容。

170

2025.10.17

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

847

2023.08.22

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

564

2023.09.20

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

510

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

204

2025.07.04

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

69

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 11.4万人学习

C 教程
C 教程

共75课时 | 5.5万人学习

C++教程
C++教程

共115课时 | 22.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号