第3章 C++语言核心考点:内存管理、智能指针、多态、模板

内存管理、智能指针、多态与模板是C++面试中最高频的四组核心能力。面试官通过它们考察你对资源生命周期、运行时多态、零开销抽象及泛型编程的理解深度。本章梳理关键概念与回答框架,助你快速构建体系化知识脉络。

四个核心考点对比
考点 核心机制 典型应用 常见陷阱
内存管理 new/delete 与 RAII 智能指针、资源池 内存泄漏、悬空指针
智能指针 引用计数、所有权 资源自动管理 循环引用、性能开销
多态 虚函数、虚表 接口设计、策略模式 对象切割、vptr额外内存
模板 泛型、元编程 STL、enable_if 代码膨胀、SFINAE可读性
智能指针问题 引用计数 原理 循环引用 weak_ptr 自定义删除器 unique_ptr特殊 性能与适用 场景判断 追问路径:从基础定义逐步深入实现细节与权衡

面试问答卡片

问题1:谈谈C++11的智能指针及其内存管理优势

面试官考察点: RAII理解、shared_ptr/unique_ptr/weak_ptr辨析、引用计数、循环引用处理
回答框架:
  1. 智能指针是RAII思想的封装,自动释放资源
  2. unique_ptr独占所有权,零开销;shared_ptr共享所有权,引用计数;weak_ptr观测不增加计数
  3. weak_ptr解决shared_ptr循环引用导致的内存泄漏
  4. 性能:unique_ptr无额外开销;shared_ptr引用计数有原子操作

简短示例回答: C++11提供三种智能指针:unique_ptr独占资源,适合所有权明确场景;shared_ptr通过引用计数实现共享,需注意循环引用;weak_ptr可观测但不拥有,打破循环。它们都确保自动释放,避免手动delete。

可能追问: 引用计数线程安全如何实现?自定义删除器如何使用?如何与C语言回调函数交互?
避坑提醒: 不要把裸指针和智能指针混用;shared_ptr循环引用一定用weak_ptr;unique_ptr可通过move转移所有权。

问题2:C++多态的实现机制是什么?虚函数表如何工作?

面试官考察点: 虚函数、虚表、动态绑定、对象内存布局、性能开销
回答框架:
  1. 多态通过虚函数实现,基类声明virtual,派生类重写
  2. 每个含虚函数的类有一个虚表(vtable),存储函数指针
  3. 对象头部增加vptr指针(8字节),指向所属类的虚表
  4. 调用时通过vptr间接跳转,实现动态绑定
  5. 构造函数不能为虚,析构函数通常设为虚

简短示例回答: 基类声明虚函数,派生类重写。每个对象拥有vptr指向类的虚表。调用时根据实际类型从虚表获取函数地址,实现运行时多态。代价是对象增加指针大小,每次调用多一次间接跳转。

可能追问: 虚表在编译时还是运行时生成?多重继承下虚表如何布局?纯虚函数如何实现接口?
避坑提醒: 构造函数中不要调用虚函数;析构函数应为虚;静态成员函数不能为虚。

问题3:解释模板特化与SFINAE

面试官考察点: 全特化/偏特化概念、函数模板与类模板差异、SFINAE原理、enable_if用法
回答框架:
  1. 模板特化:全特化指定所有类型参数;偏特化部分指定(仅类模板支持)
  2. 函数模板只有全特化,没有偏特化(可通过重载模拟)
  3. SFINAE:替换失败不是错误,编译器忽略无效重载
  4. 常用std::enable_if对模板函数进行条件编译

简短示例回答: 全特化如 template<> class MyClass<int> {...}。偏特化如 template<class T> class MyClass<T*> {...}。SFINAE指当模板参数替换产生非法类型时,编译器不报错而移除该重载。例如 std::enable_if<std::is_integral_v<T>> 实现整数类型专用函数。

可能追问: 偏特化为什么不能用于函数模板?SFINAE与concepts的对比?可变参数模板如何与SFINAE组合?
避坑提醒: 函数模板偏特化用重载代替;偏特化匹配优先级易混淆;复杂SFINAE改用concepts提升可读性。