c++怎么实现数组的深拷贝_c++ memcpy与循环赋值【详解】

2次阅读

深拷贝数组必须手动分配新内存并逐元素复制;原生数组不支持深拷贝语义,直接赋值会编译错误;new+循环赋值安全通用,malloc+memcpy仅适用于POD类型;memcpy不调用构造/析构函数,误用于非POD类型(如std::String)将导致悬空指针

c++怎么实现数组的深拷贝_c++ memcpy与循环赋值【详解】

深拷贝数组必须自己分配新内存

c++ 中,原生数组(如 int arr[10])本身不支持“深拷贝”语义——它没有拷贝构造函数赋值运算符。所谓“深拷贝数组”,本质是:申请一块**独立的新内存**,再把原数组内容逐字节或逐元素复制过去。如果你直接写 arr2 = arr1(对原生数组),编译器会报错;如果用指针或动态数组,不手动 new + copy,就只是浅拷贝(两个指针指向同一块内存)。

常见错误现象:delete[] ptr1 后再访问 ptr2,触发野指针崩溃;或修改 ptr2[i] 却意外改了 ptr1[i]

  • 使用 new + 循环赋值:安全、可读、支持类类型(调用构造/析构)
  • 使用 malloc + memcpy:仅适用于 POD 类型(如 intdouble、纯 C 结构体),不调用构造/析构函数
  • 避免 std::Arraystd::vector 时还手写拷贝——它们默认就是深拷贝

memcpy 只适合 POD 类型的按字节拷贝

memcpy 是 C 标准库函数,行为是“从 src 地址开始,连续复制 n 字节到 dst”。它不管数据类型,也不调用任何构造函数或析构函数。这意味着:只要源和目标内存布局一致、且对象不含指针/虚表/非平凡成员,memcpy 才等价于深拷贝。

典型误用:memcpy(dst, src, sizeof(std::string)) —— std::string 内部有指针,memcpy 只复制了指针值,造成双重释放或悬空引用。

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

  • ✅ 安全:复制 int*double[100]Struct { int x; Float y; }*
  • ❌ 危险:复制含 std::stringstd::vector虚函数、自定义构造函数的类对象
  • 参数顺序固定:memcpy(dst, src, n),别把 src 和 dst 写反,也别忽略 n 是字节数(不是元素个数)

循环赋值更通用,但要注意构造语义

对动态分配的数组(如 T* src = new T[n]),用循环做深拷贝是最直观的方式:

for (int i = 0; i < n; ++i) {     dst[i] = src[i]; // 调用 T 的拷贝赋值运算符 }

这行代码是否真正完成深拷贝,取决于 T 自身的实现。例如:

  • T = int:简单赋值,效果同 memcpy
  • T = std::string:调用 std::string::operator=,内部会重新分配内存,真正深拷贝字符串内容
  • T 是自定义类:需确保已正确定义拷贝赋值运算符(或依赖编译器生成的,默认行为对含指针成员仍是浅拷贝)

性能上,循环比 memcpy 稍慢(函数调用开销、可能的分支),但语义明确、类型安全、可调试。

最容易被忽略的点:析构与所有权归属

无论用 memcpy 还是循环,你手动分配了内存(new T[n]),就必须手动释放(delete[] ptr)。C++ 不会自动追踪谁拥有这块内存。

更隐蔽的问题是:如果原数组里存的是指针(如 MyClass** arr),那“深拷贝数组”到底要不要也深拷贝每个 MyClass* 指向的对象?这完全由业务逻辑决定,memcpy 和循环都只处理第一层——它们复制的是指针值,不是指针所指内容。

建议:除非有极致性能要求且确认是 POD,否则优先用 std::vector。它的拷贝构造自动完成深拷贝,内存管理零出错风险。

text=ZqhQzanResources