应使用 std::vector 替代裸数组以避免手动深拷贝问题:vector 默认深拷贝元素,对含指针成员的自定义类型需正确实现拷贝控制,智能指针可简化资源管理但不自动深拷贝。

用 std::vector 替代裸数组,避免手动深拷贝
裸数组(如 int arr[10])本身不支持拷贝语义,= 或传参只会复制指针或触发隐式数组退化,根本谈不上“深度拷贝”。真正需要深拷贝的,几乎都是指向堆内存的指针数组或含指针成员的对象数组。直接用 std::vector 是最省心的选择——它默认就做深拷贝:
std::vector<:string> v1 = {"hello", "world"};<br>std::vector<:string> v2 = v1; // 深拷贝:每个 string 的内部 buffer 都被独立复制</:string></:string>如果元素类型是自定义类,确保其拷贝构造函数和赋值运算符正确处理了动态资源(比如 new 出来的内存)。手动深拷贝指针数组时,必须逐个 new 并管理生命周期
假设你有 int** matrix 表示二维动态数组,matrix[i] 是每行首地址。直接 memcpy(matrix, src, sizeof(int*) * rows) 只复制指针,不是深拷贝。正确做法是:
- 先分配新指针数组:
int** dst = new int*[rows]; - 再对每行分别分配并拷贝:
for (int i = 0; i - 必须配套写析构逻辑(或改用
std::unique_ptr<int>[]</int>),否则必然内存泄漏
new 或对应 delete[],都会导致未定义行为或崩溃。含指针成员的结构体数组,深拷贝依赖正确的拷贝控制成员
比如:
<pre class="brush:php;toolbar:false;">struct Data {<br> int* ptr;<br> Data() : ptr(nullptr) {}<br> Data(const Data& other) : ptr(other.ptr ? new int(*other.ptr) : nullptr) {}<br> Data& operator=(const Data& other) {<br> if (this != &other) {<br> delete ptr;<br> ptr = other.ptr ? new int(*other.ptr) : nullptr;<br> }<br> return *this;<br> }<br> ~Data() { delete ptr; }<br>};此时 std::vector<data> v1(10); std::vector<data> v2 = v1;</data></data> 才会真正深拷贝每个 ptr 指向的内容。缺了拷贝构造函数或赋值运算符,编译器生成的默认版本只做浅拷贝,两个对象会共享同一块 int* 内存。用 std::unique_ptr 或 std::shared_ptr 简化资源管理
裸指针深拷贝容易出错,现代 C++ 更推荐用智能指针表达所有权意图:
-
std::vector<:unique_ptr>> arr(rows);</:unique_ptr>—— 每个unique_ptr独占一行内存,拷贝时需显式std::make_unique复制内容 -
std::vector<:shared_ptr>></:shared_ptr>—— 共享语义下,“拷贝”只是增加引用计数,不是深拷贝;真要深拷贝得std::make_shared<:string>(*ptr)</:string> - 注意:
std::shared_ptr的拷贝开销略高(原子操作),而std::unique_ptr移动快、拷贝被禁用,强制你思考复制逻辑
shared_ptr,它解决的是共享生命周期问题,不是自动深拷贝。深拷贝的本质是资源隔离,不是语法糖。哪怕用了 std::vector,只要里面存的是裸指针,照样要自己写深拷贝逻辑。最容易被忽略的,是自定义类型中指针成员的初始化状态(比如 nullptr)是否在拷贝构造里被正确处理——漏判空指针,new int(*other.ptr) 就会崩。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











