字节 客户端-C++ 一面凉经
1. 智能指针是如何工作的,尤其是 unique_ptr?
unique_ptr` 是独占所有权模型:同一时刻只能有一个指针拥有对象。 它的核心机制是:
- 构造时接管裸指针;
- 禁止拷贝(防止多重释放);
- 允许移动(转移所有权);
- 析构时自动 delete(RAII)。
适用场景:资源生命周期清晰、无需共享所有权的对象管理(默认首选)。
代码:
#include <memory>
#include <iostream>
struct A {
~A() { std::cout << "A destroyed\n"; }
};
int main() {
std::unique_ptr<A> p1 = std::make_unique<A>();
// std::unique_ptr<A> p2 = p1; // 编译错误:禁止拷贝
std::unique_ptr<A> p2 = std::move(p1); // 所有权转移
return 0; // p2 离开作用域自动释放
}
2. weak_ptr 是如何解决循环引用问题的?
循环引用常见于 shared_ptr 双向持有:A 持有 B,B 又持有 A,引用计数无法归零。 weak_ptr 不增加引用计数,只做“观察者”,从而打破环。
代码:
#include <memory>
struct B;
struct A {
std::shared_ptr<B> b;
};
struct B {
std::weak_ptr<A> a; // 关键:不用 shared_ptr
};
int main() {
auto a = std::make_shared<A>();
auto b = std::make_shared<B>();
a->b = b;
b->a = a; // 不增加 A 的强引用计数
}
3. 智能指针的回收机制会有额外开销吗?会触发额外操作吗?
会,有但可控:
- shared_ptr 有引用计数维护(通常是原子操作),高并发下有开销;
- 控制块分配也有额外内存与 cache 开销;
- 析构时会调用对象析构函数和 deleter(可能触发复杂释放逻辑)。
unique_ptr 开销很低,接近裸指针语义(主要是析构时自动释放)。
4. 你实现的“实时消息路由网关”是基于开源框架设计的吗?
是参考了开源思想,但不是直接套壳。 我做法是:
- 借鉴 Reactor、线程模型、连接管理等成熟模式;
- 针对业务场景重写协议编解码与路由策略;
- 自建可观测性(链路打点、队列水位、慢请求分析)。 这样既能复用成熟经验,又避免“框架特性和业务不匹配”的问题。
5. 中心式架构有哪些缺点?如何解决?
中心式(单中心调度/存储)常见问题:
- 单点故障风险高;
- 横向扩展能力弱;
- 热点集中导致延迟抖动。
改进方式:
- 去中心化或多中心容灾;
- 分片 + 副本;
- 读写分离与异步削峰;
- 引入一致性协议(按业务需求选择强一致或最终一致)。
6. 你在网关里为什么选择 Reactor 而不是 Proactor?
我的选择标准是平台支持与工程复杂度:
- Linux 下 epoll + 非阻塞 I/O 的 Reactor 更成熟、可控;
- Proactor 模型在不同平台实现差异较大,统一成本高。 对于高并发网关,Reactor 在可维护性和调优手段上更适合团队当前阶段。
7. 在分布式处理中有哪些需要注意的点?
关键是“先承认不可靠,再设计兜底”:
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
C++ 常考面试题总结 文章被收录于专栏
本专栏系统梳理C++方向, 大中厂高频高频面试考点 , 内容皆来自真实面试经历,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力.
查看14道真题和解析