全面理解-深拷贝与浅拷贝

news/2025/2/25 20:33:36

在 C++ 中,深拷贝(Deep Copy) 和 浅拷贝(Shallow Copy) 是两种完全不同的对象拷贝策略,主要区别在于对指针和动态分配资源的处理方式。正确理解二者的区别是避免内存泄漏、悬空指针和程序崩溃的关键。


一、核心区别

特性浅拷贝(Shallow Copy)深拷贝(Deep Copy)
拷贝内容仅复制指针值(地址),不复制指针指向的内存数据复制指针指向的实际数据,并为新对象分配独立内存
内存所有权多个对象共享同一块内存每个对象拥有独立内存
资源管理风险容易导致双重释放(double free)或悬空指针内存隔离,安全可靠
默认行为C++ 默认的拷贝构造函数和赋值运算符是浅拷贝需手动实现
适用场景对象不含动态资源或明确需要共享数据对象管理动态分配的资源(如数组、文件句柄等)

二、示例解析

1. 浅拷贝的陷阱
class ShallowArray {
public:
    int* data;
    size_t size;
    
    ShallowArray(size_t n) : size(n), data(new int[n]) {}
    ~ShallowArray() { delete[] data; }
};

int main() {
    ShallowArray arr1(5);
    ShallowArray arr2 = arr1; // 默认浅拷贝(复制指针)
    
    // 析构时 arr1 和 arr2 的 data 指向同一内存,导致双重释放!
}
2. 深拷贝的实现
class DeepArray {
public:
    int* data;
    size_t size;
    
    DeepArray(size_t n) : size(n), data(new int[n]) {}
    
    // 深拷贝构造函数
    DeepArray(const DeepArray& other) : size(other.size), data(new int[other.size]) {
        std::copy(other.data, other.data + size, data);
    }
    
    // 深拷贝赋值运算符
    DeepArray& operator=(const DeepArray& other) {
        if (this != &other) {
            delete[] data;
            size = other.size;
            data = new int[size];
            std::copy(other.data, other.data + size, data);
        }
        return *this;
    }
    
    ~DeepArray() { delete[] data; }
};

int main() {
    DeepArray arr1(5);
    DeepArray arr2 = arr1; // 深拷贝,独立内存
    // 安全析构
}

三、深拷贝的必要性

当对象包含以下资源时 必须使用深拷贝

  1. 动态分配的内存new/malloc 申请)

  2. 文件句柄(需独立打开/关闭)

  3. 网络连接(需独立管理)

  4. 线程锁(避免多个对象共享同一锁)


四、如何正确实现深拷贝

1. 拷贝构造函数
// 深拷贝构造函数
ClassName(const ClassName& other) {
    // 分配新资源
    resource = new ResourceType(*other.resource); 
    // 或拷贝数据
    std::memcpy(data, other.data, size);
}
2. 赋值运算符
ClassName& operator=(const ClassName& other) {
    if (this != &other) { // 处理自我赋值
        // 释放旧资源
        delete resource;
        // 分配新资源并拷贝数据
        resource = new ResourceType(*other.resource);
    }
    return *this;
}

五、浅拷贝的合理使用场景

以下情况 浅拷贝是安全的

  1. 对象仅包含基本数据类型(intdouble 等)

  2. 对象包含指针但 不拥有所有权(如观察者指针)

  3. 明确需要共享数据(需配合引用计数或智能指针)


六、现代 C++ 的替代方案

1. 使用智能指针
  • std::unique_ptr:禁止拷贝,强制移动语义(隐式深拷贝替代)

  • std::shared_ptr:共享所有权,引用计数自动管理资源

class SafeArray {
    std::unique_ptr<int[]> data; // 自动管理内存
    size_t size;
public:
    SafeArray(size_t n) : size(n), data(std::make_unique<int[]>(n)) {}
    // 默认禁用拷贝(需深拷贝时手动实现)
};
2. 使用容器类
  • std::vectorstd::string 等标准容器已实现深拷贝

std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = v1; // 自动深拷贝

七、总结

操作浅拷贝深拷贝
资源所有权共享资源独占资源
内存开销小(仅复制指针)大(复制所有数据)
安全性低(需额外管理共享资源)高(资源隔离)
实现复杂度无需额外实现(默认行为)需手动实现拷贝构造函数和赋值运算符

核心原则

  • 若对象管理资源(如动态内存),必须实现深拷贝。

  • 优先使用智能指针和标准容器,减少手动内存管理。


http://www.niftyadmin.cn/n/5865926.html

相关文章

人工智能 阿里云算力服务器的使用

获取免费的阿里云服务器 阿里云免费使用地址&#xff1a; https://free.aliyun.com/ 选择 人工智能平台 PAI 选择交互式建模 再选建立实例。 选择对应的GPU 和镜像&#xff0c;点击确认。 注意&#xff1a;250个小时&#xff0c;用的时候开启&#xff0c;不用的时候关闭&…

虚拟机PING不通百度?NAT是什么?什么仅主机?

在虚拟机经常遇到一些网络问题&#xff0c;我也遇到了很多问题&#xff0c;在经过无数次试错后&#xff0c;我对这些有了一定的了解&#xff0c;和解决方式&#xff0c;下面我来谈谈我的经验&#xff0c;如有错误&#xff0c;请轻喷 下面都是我的口语&#xff0c;非正式&#…

LabVIEW中CFURL.llb 工具库说明

CFURL.llb 是 LabVIEW 2019 安装目录下 C:\Program Files (x86)\National Instruments\LabVIEW 2019\vi.lib\Platform\ 路径下的工具库&#xff0c;主要用于处理 LabVIEW 与 URL 相关的操作&#xff0c;涵盖 URL 解析、HTTP 请求发送、数据传输等功能模块&#xff0c;帮助开发者…

屏幕闪烁,相机能不能达到人眼视觉效果

你看着一个灯&#xff0c;光线稳定。然后你用相机拍照&#xff0c;结果发现有时并无光线。 你看着电子屏有字&#xff0c;用手机照相&#xff0c;只有部分字。如附图。 我想问&#xff0c;能不能从技术上改进&#xff0c;让照片、录像屏幕达到人眼视觉效果&#xff1f;

图像处理案例06 OCR应用

OCR应用 1 OCR读取账单1.1 背景及思路1.2 代码 1 OCR读取账单 1.1 背景及思路 思路 目标是读取图片中账单的信息。首先要截取图片上的账单&#xff0c;考虑到账单并非都是整齐摆放&#xff0c;为了保持算法的通用性&#xff0c;通过透视变换对扣取的账单摆正&#xff0c;然后调…

Unity汽车笔记

汽车的移动和转向 我们知道&#xff0c;汽车的前进后退是变速运动。按w&#xff0c;汽车开始加速&#xff0c;到最大速度后保持匀速&#xff0c;松开w&#xff0c;汽车受到阻力加速。如果按s减速&#xff0c;则以更大的加速度减速。后退反之。 按A/D时前轮偏转。只有前进后退…

基于 Vue.js 和 Element UI 实现九宫格按钮拖拽排序功能 | 详细教程与代码实现

在Vue.js项目中使用vue-element-template&#xff08;基于Element UI&#xff09;实现按钮的九宫格拖拽排序功能&#xff0c;可以通过以下步骤实现。我们将使用vuedraggable库来实现拖拽排序功能。 1. 安装依赖 首先&#xff0c;确保你已经安装了vuedraggable库&#xff1a; …

Python Seaborn库使用指南:从入门到精通

1. 引言 Seaborn 是基于 Matplotlib 的高级数据可视化库,专为统计图表设计。它提供了更简洁的 API 和更美观的默认样式,能够轻松生成复杂的统计图表。Seaborn 在数据分析、机器学习和科学计算领域中被广泛使用。 本文将详细介绍 Seaborn 的基本概念、常用功能以及高级用法,…