跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

C++中的浅拷贝和深拷贝有什么区别?(指针地址复制与堆内存独立申请)

浅拷贝仅复制指针值,导致多对象共享同一内存,引发use-after-free或double free;深拷贝需重载拷贝构造、赋值运算符和析构函数,手动分配并复制内存;现代C++推荐用vector、string或unique_ptr替代裸指针。 浅拷贝只是复制指针值,不是复制它指向的内容 当你用默认拷贝构造函数或赋值运算符处理含
int*
这类裸指针的类时,编译器只做位拷贝:把原对象里指针变量的值(即内存地址)直接复制过去。两个对象的指针成员指向同一块堆内存。 这会导致后续操作出问题,比如其中一个对象析构时调用
delete
,另一对象再访问该指针就会触发
use-after-free
;或者两个对象都尝试
delete
同一块内存,引发
double free
错误。 常见错误现象: 程序在第二次
delete
时崩溃(glibc 报
double free or corruption
) 修改一个对象的数据,另一个对象的对应字段也跟着变 Valgrind 报告
Invalid read/write
Use of uninitialised value
深拷贝需要手动申请新堆内存并逐 字节 复制内容 实现深拷贝的关键是:在拷贝构造函数和
operator=
中,不复用原指针,而是用
new
分配一块大小相同的新内存,再用
memcpy
或循环把原数据拷过去。 立即学习 “ C++免费学习笔记(深入) ”; 必须同时满足三个条件,才算完整实现深拷贝: 重载拷贝构造函数,内部用
new
分配内存 +
std::copy
或循环复制数据 重载赋值运算符,先检查自赋值(
if (this == &other)
),再释放当前内存,再分配+复制 重载析构函数,确保用
delete[]
(对数组)或
delete
(对单个对象)释放自己申请的内存 漏掉任意一项,都可能造成内存泄漏、重复释放或悬空指针。 C函数速查手册(CHM版) C函数速查手册(CHM版) 下载 现代 C++ 更推荐用智能指针或容器替代裸指针 手写深拷贝容易出错,且难以兼顾异常安全。C++11 起,应优先用
std::vector
std::string
std::unique_ptr
替代裸指针管理堆内存。 例如:
class Data { private: std::vector data_; // 自动深拷贝,无需手写拷贝函数 public: Data(const std::vector& d) : data_(d) {} // 编译器生成的拷贝构造函数已正确处理深拷贝 };
若必须用裸指针,至少用
std::unique_ptr
,它的拷贝被禁用,移动时自动转移所有权,从根本上避免浅拷贝误用。 调试时怎么快速判断是不是浅拷贝导致的问题 观察两个对象中指针成员的地址值是否一致:
Data a({1,2,3}); Data b = a; // 假设未定义拷贝构造函数 std::cout << "a.ptr: " << (void*)a.ptr_ << "\n"; std::cout << "b.ptr: " << (void*)b.ptr_ << "\n"; // 若输出相同地址,就是浅拷贝
更可靠的方式是用 AddressSanitizer 编译运行:
g++ -fsanitize=address -g
,它会在发生
use-after-free
double-free
时直接打印栈回溯。 真正麻烦的不是写深拷贝,而是忘记写——只要类里有裸指针或
FILE*
等资源句柄,就必须显式定义三法则(拷贝构造、赋值、析构),否则默认行为几乎总是错的。

相关文章