博雷顿科技股份公司 C++ 一面复盘

1. 自我介绍

我之前在某某公司实习,主要参与 C++ 后端相关开发工作。 实习期间参与消息处理和服务端模块开发,涉及功能迭代、问题排查和性能优化。 技术栈以 C/C++ 为主,熟悉 STL、Linux 多线程和网络编程(TCP/IP),了解 MySQL、Redis 组件。 整体偏工程实践,关注代码质量、稳定性及性能优化,期待在 C++ 后端方向继续提升

2. 项目介绍

我参与开发了一个分布式实时流处理平台,负责事件数据的实时计算和多维聚合。项目难点在于高并发写入时线程锁竞争严重,导致延迟不稳定;同时状态同步复杂,内存容易泄漏。

我主要通过以下方式解决了问题:

  • 用无锁队列替代传统锁,减少线程竞争。
  • 设计分段锁和读写锁,热点数据分离访问。
  • 实现轻量快照机制保障状态一致性。
  • 优化内存管理,防止碎片和泄漏。
  • 使用监控工具定位性能瓶颈并针对性优化。

通过这个项目,我掌握了高性能并发编程和分布式状态管理方法,提升了系统调优和问题定位能力。优化后延迟降低 40%,系统稳定性明显提升。

3. 栈与队列的区别

  • 栈(Stack):后进先出(LIFO),只能在栈顶操作。
  • 队列(Queue):先进先出(FIFO),元素从尾部入队,头部出队。

4. 栈与堆的区别

  • 栈由系统自动管理,空间小,效率高,存储函数调用和局部变量。
  • 堆由程序员管理(new/delete 或智能指针),空间大但分配释放开销大。

5. AVL 树

  • 一种自平衡二叉搜索树,节点左右子树高度差最大为 1。
  • 通过旋转操作维持平衡,保证查找/插入/删除时间复杂度为 O(log n)。

6. map 和 unordered_map

  • map 基于红黑树,有序,O(log n) 复杂度。
  • unordered_map 基于哈希表,无序,平均 O(1) 复杂度,最坏情况 O(n)。

7. 如何判断链表有环?

  • 使用快慢指针(Floyd 判圈算法),快指针每次走两步,慢指针走一步。
  • 若快慢指针相遇,则链表存在环;否则无环。

8. 多态的原理

  • C++ 运行时多态通过虚函数实现。
  • 编译器为虚函数类生成虚函数表(vtable),对象含虚表指针(vptr)。
  • 通过基类指针或引用调用虚函数时,动态绑定到派生类实现。

9. 智能指针

  • unique_ptr 独占资源所有权,支持移动不支持复制。
  • shared_ptr 共享资源所有权,计数管理。
  • weak_ptr 弱引用,不增加计数,用于解决循环引用。

10. C++17 新特性

  • 结构化绑定(auto [a,b] = ...;)
  • if constexpr
  • std::optional
  • std::variant
  • std::string_view

11. 用过哪些容器?

  • 顺序容器:vector、deque、list
  • 关联容器:map、set、unordered_map、unordered_set
  • 容器适配器:stack、queue、priority_queue

12. LRU 缓存设计(代码题)

题目描述 设计并实现一个容量有限的 LRU 缓存:支持 get(key) 和 put(key, value),均需 O(1) 时间复杂度。

关键思路

  • 哈希表快速定位缓存项。
  • 双向链表维护访问顺序,新访问的节点移动到头部,容量满时淘汰尾部节点。
#include <unordered_map>
#include <list>

class LRUCache {
public:
    LRUCache(int capacity): capacity_(capacity) {}

    int get(int key) {
        auto it = cache_.find(key);
        if (it == cache_.end()) return -1;
        nodes_.splice(nodes_.begin(), nodes_, it->second);
        return it->second->second;
    }

    void put(int key, int value) {
        auto it = cache_.find(key);
        if (it != cache_.end()) {
            it->second->second = value;
            nodes_.splice(nodes_.begin(), nodes_, it->second);
        } else {
            if ((int)nodes_.size() == capacity_) {
                int old_key = nodes_.back().first;
                nodes_.pop_back();
                cache_.erase(old_key);
            }
            nodes_.emplace_front(key, value);
            cache_[key] = nodes_.begin();
        }
    }

private:
    int capacity_;
    std::list<std::pair<int,int>> nodes_;
    std::unordered_map<int, std::list<std::pair<int,int>>::iterator> cache_;
};

测试示例

int main() {
    LRUCache cache(2);
    cache.put(1, 1);
    cache.put(2, 2);
    std::cout << cache.get(1) << "\n";   // 输出1
    cache.put(3, 3);                      // 淘汰key=2
    std::cout << cache.get(2) << "\n";   // 输出-1
    cache.put(4, 4);                      // 淘汰key=1
    std::cout << cache.get(1) << "\n";   // 输出-1
    std::cout << cache.get(3) << "\n";   // 输出3
    std::cout << cache.get(4) << "\n";   // 输出4
    return 0;
}

13. 追问

  • 构造函数可以是虚函数吗? 不可以,构造函数是在对象创建时调用,没有多态需求,且编译器不支持。
  • 析构函数可以是虚函数吗? 可以,基类通常应声明虚析构函数,避免通过基类指针删除派生类对象时资源泄露。
  • vector 中可以存 unique_ptr 吗? 可以,但需要用移动语义插入,如 push_back(std::move(ptr)) 或emplace_back()。

14. 反问

问了问团队主要业务方向和技术栈是什么 , 新人前三个月的培训和考核重点如何, 是否有师兄带和代码评审机制 ; 团队性能优化常用哪些工具?排查流程是什么样的?

#有必要和同事成为好朋友吗?#
C++面试总结 文章被收录于专栏

本专栏系统梳理C++面试高频考点,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力。

全部评论

相关推荐

2025-12-28 20:47
已编辑
北京工商大学 Java
程序员牛肉:我靠你这个实习经历其实最需要担心的点是你做的太多了,可能会被面试官怀疑是你伪造的。 交易状态机是你做的,支付多渠道是你做的,对账是你做的,结算还是你做的,重复支付也是你做的,整个服务的异常处理也是你做的。 其实你这个反而问题很大的,你想想站在面试官的角度,他是真的会相信你的能力很强,还是相信这份实习你伪造了大部分?我相信你真的做了这么多,但是删一些,废话删一删。你这个做的太多了反而真实性不可信。 后面再补一个项目,在github上找一个高star的项目学一学然后写到自己简历上。我觉得你能力肯定没问题。28届能做到这个份上很厉害,但是在求职市场中,你不是在跟28届的同学比,把你这个简历放到27届其实也就一般水平。 所以后续要想一想看看能不能给自己简历上搞点亮点,比如开源贡献呢?比如博客呢?
实习要如何选择和准备?
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务