c++中如何进行深拷贝与浅拷贝_c++深浅拷贝区别

14次阅读

浅拷贝是按字节复制对象内存,深拷贝需手动实现以避免指针共享;当类含裸指针、自定义深拷贝成员或独占资源时必须重写拷贝构造函数赋值运算符并遵循三/五法则。

c++中如何进行深拷贝与浅拷贝_c++深浅拷贝区别

浅拷贝就是按字节复制对象内存,深拷贝要自己重写拷贝构造函数

默认情况下,c++ 的拷贝构造函数和赋值运算符只做浅拷贝:它把源对象的每个字节原样复制到新对象里。如果类里有 char*int* 这类裸指针成员,浅拷贝会让两个对象指向同一块内存——后续一个对象析构时 delete 了,另一个再访问或再次 delete 就会崩溃或未定义行为。

什么时候必须手动实现深拷贝

当类中存在以下任一情况时,编译器自动生成的拷贝构造函数就不够用了:

  • 成员变量是裸指针(如 char*int*),且指向的是 new 出来的堆内存
  • 成员变量是自定义类对象,而该类本身已定义了深拷贝逻辑(此时你得在当前类中调用它的拷贝构造)
  • 资源需要独占(比如文件句柄、socket 描述符),不能共享

典型例子:

class String { private:     char* data_;     size_t len_; public:     String(const char* s) : len_(strlen(s)) {         data_ = new char[len_ + 1];         strcpy(data_, s);     }     // ❌ 缺少深拷贝构造函数 → 浅拷贝导致 double free     String(const String& other) : len_(other.len_) {         data_ = other.data_; // 危险!仅复制指针值     }     ~String() { delete[] data_; } };

深拷贝的正确写法:三步走

实现深拷贝的核心是「分配新内存 + 复制内容 + 独立管理」。以 String 类为例:

  • 在拷贝构造函数里用 newdata_ 分配等长新内存
  • strcpystd::copy 把原内容逐字节复制过去
  • 务必同步更新所有相关成员(如 len_),别漏掉
  • 如果类还支持赋值运算符(operator=),也得同样处理,并注意自我赋值检查(if (this == &other) return *this;

修正后的构造函数:

String(const String& other) : len_(other.len_) {     data_ = new char[len_ + 1];     strcpy(data_, other.data_); }

现代 C++ 更推荐用 RaiI 容器替代裸指针

手动管理深拷贝容易出错,而且要同时写拷贝构造、赋值、析构(即“三法则”,C++11 后是“五法则”)。更安全的做法是直接用标准库类型:

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

  • std::string 替代 char*,它内部已实现深拷贝
  • std::vector 替代 int* + size_t 计数
  • std::unique_ptr 表示独占所有权,移动语义天然避免浅拷贝歧义

这样连拷贝构造函数都不用写,编译器生成的版本就完全安全。但如果你正在封装底层资源、写基础库、或面试被问到原理,那就绕不开手动深拷贝的细节。

最容易被忽略的一点:深拷贝不是只改构造函数,还要同步检查 operator= 和移动操作是否破坏了资源独占性——尤其当类开始支持移动语义后,浅拷贝逻辑可能意外残留在移动路径里。

text=ZqhQzanResources