问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

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

创作时间:
作者:
@小白创作中心

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

引用
CSDN
1.
https://m.blog.csdn.net/hl_love_c/article/details/145699198

在C++编程中,深拷贝和浅拷贝是两个非常重要的概念,它们直接影响着程序的内存管理和运行安全。本文将从多个维度深入解析这两个概念的区别、应用场景以及正确的实现方法,帮助开发者避免常见的内存泄漏和悬空指针问题。

在 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; // 自动深拷贝

七、总结

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

核心原则

  • 若对象管理资源(如动态内存),必须实现深拷贝。
  • 优先使用智能指针和标准容器,减少手动内存管理。
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号