卡码笔记-最强八股文
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
代码随想录 (opens new window)
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
代码随想录 (opens new window)
  • 本栏必读

    • 关于本专栏
    • C++学习路线
    • C++面试题系优化
  • 基础与语法

  • 面向对象

    • C++构造函数有几种,分别什么作用?
    • 什么是构造函数和析构函数?构造函数和析构函数可以是虚函数吗?为什么?
    • C++的重载和重写,以及它们的区别和实现方式
    • C++怎么实现多态
    • C++中的虚函数和纯虚函数有什么区别?
    • 虚函数怎么实现的?
    • 多重继承的优缺点及菱形继承问题
    • 如何禁止一个类被继承
    • 深拷贝和浅拷贝的区别?
      • 简要回答
      • 详细回答
      • 知识拓展
    • this指针的原理
    • C++如何实现一个单例模式?
  • STL 与容器

  • 内存管理

  • C++11 与现代 C++

  • 智能指针

  • 并发与 I/O

# 深拷贝与浅拷贝

面试官问:"深拷贝和浅拷贝有什么区别?什么时候必须用深拷贝?"

这题看起来简单,但很多人只能说出"浅拷贝复制指针,深拷贝复制内容",问到内存模型层面的原因、什么场景会出问题、怎么和智能指针配合,就答不上来了。关键是从内存布局的角度理解两者的本质差异。

# 简要回答

浅拷贝:只复制对象的成员变量值。对于指针成员,复制的是地址本身,两个对象的指针指向同一块堆内存。

深拷贝:为指针成员重新分配内存并复制内容,两个对象各自拥有独立的堆内存,互不影响。

核心问题:浅拷贝导致两个对象共享同一块堆内存,任何一个对象析构时 delete 这块内存,另一个对象的指针就变成悬垂指针——再次 delete 就是双重释放,程序崩溃。

# 详细回答

编译器默认生成的拷贝构造函数是浅拷贝

编译器自动生成的拷贝构造函数和赋值运算符,做的是逐成员复制(memberwise copy)。对于 int、double 这些值类型没问题,但对于指针成员,复制的只是地址值——两个对象的指针指向同一块内存。

浅拷贝的致命问题

当类管理动态内存(new 出来的资源)时,浅拷贝会导致:

  • 双重释放:两个对象析构时都 delete 同一块内存,程序崩溃
  • 悬垂指针:一个对象析构后,另一个对象的指针指向已释放的内存,访问就是未定义行为
  • 意外修改:通过一个对象修改数据,另一个对象的数据也被改了

深拷贝的实现

当类包含指针成员且管理动态内存时,必须手动实现:拷贝构造函数、赋值运算符、析构函数——这就是 C++ 的 Rule of Three。拷贝构造和赋值运算符中,为指针成员 new 新内存,把原对象指向的内容复制过来。这样两个对象各自拥有独立的内存,析构时各自释放,互不干扰。

现代 C++ 的替代方案

C++11 之后,用 unique_ptr 或 shared_ptr 管理动态内存,可以避免手写深拷贝。unique_ptr 禁止拷贝(只能移动),从根本上避免共享问题;shared_ptr 用引用计数自动管理生命周期,多个对象可以安全共享同一块内存。

深拷贝与浅拷贝内存模型对比

# 知识拓展

面试官可能追问:

Q1: 什么时候必须写深拷贝?

只要类里有裸指针(T*)并且这个指针指向的内存是类自己 new 出来的,就必须写深拷贝。判断标准很简单:如果你写了析构函数里有 delete,那就一定要写拷贝构造和赋值运算符(Rule of Three)。如果类里只有值类型成员或者智能指针,编译器默认的浅拷贝就够用。

Q2: STL 容器存自定义对象时,拷贝语义有什么坑?

STL 容器是值语义,push_back 会触发拷贝构造。如果你的类有裸指针但没写深拷贝,容器里的对象和外面的对象共享内存,容器扩容时旧元素析构会释放内存,新元素的指针就悬空了——直接崩溃。解决方案:要么实现深拷贝,要么用智能指针管理资源,要么存指针而不是对象。

Q3: 写时复制(COW)是什么?和深拷贝什么关系?

写时复制是一种优化策略:拷贝时先做浅拷贝(共享内存),只有当某个对象要修改数据时,才真正做深拷贝。用引用计数跟踪有多少对象共享同一块内存,修改前检查计数——如果大于 1,先复制一份再改。早期的 std::string 实现就用了 COW,但因为多线程下引用计数的原子操作开销太大,C++11 之后标准库不再使用这种策略。

Q4: 移动语义和深拷贝是什么关系?

移动语义是 C++11 引入的第三种选择——既不是浅拷贝(共享资源),也不是深拷贝(复制资源),而是转移资源所有权。移动构造函数把源对象的指针"偷过来",然后把源对象的指针置空。代价从 O(n) 的深拷贝降到 O(1) 的指针赋值。当你不再需要源对象时(比如函数返回临时对象),移动比深拷贝高效得多。

Last Updated: 5/23/2026, 4:51:07 PM

← 如何禁止一个类被继承 this指针的原理 →

评论

验证登录状态...

侧边栏 侧边栏
夜间模式 夜间
卡码简历 卡码简历
代码随想录 代码随想录
卡码投递表 卡码投递表🔥
2026实习校招群 2026群
添加客服微信 2026实习校招客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记 支持卡码笔记
鼓励/支持/赞赏Carl 卡码笔记赞赏码
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪