荣耀 通用软件开发-C++ 二面

1. 自我介绍

2. 你在实习里做过的最复杂的模块是什么,难点在哪里

3. 如果让你设计一个配置热更新系统,你会怎么保证正在处理的请求不受影响

答案:

  • 新配置可以安全生效
  • 正在处理中的请求继续使用它开始处理时看到的那份配置

比较常见的做法是 快照 + 原子切换

思路是:

  • 当前业务线程始终读取一个稳定版本的配置快照
  • 配置更新时,不在原对象上直接修改
  • 而是构造一个新的配置对象
  • 校验通过后,再用原子方式把“当前版本指针”切到新对象
  • 老版本由正在使用它的线程继续持有,等没有引用后再释放

这样做的好处是:

  • 读路径简单
  • 不需要长时间锁住整个配置结构
  • 不会让业务线程读到半更新状态
  • 回滚也更容易做

代码:

#include <atomic>
#include <memory>
#include <string>
using namespace std;

struct Config {
    string version;
    string data;
};

class ConfigCenter {
public:
    shared_ptr<Config> get() const {
        return atomic_load(&cur_);
    }

    void publish(const shared_ptr<Config>& next) {
        atomic_store(&cur_, next);
    }

private:
    shared_ptr<Config> cur_;
};

4. 你觉得配置热更新里最容易踩的坑是什么

答案:我觉得最容易踩的坑主要有这几类:

  • 原地修改共享对象:读线程可能读到中间状态
  • 更新链路缺少校验:错误配置直接生效,影响面很大
  • 回滚机制不完整:一旦新版本异常,无法快速恢复
  • 通知和实际生效不同步:看起来“已经发布”,实际上部分实例没更新
  • 灰度规则和配置版本耦合过深:导致排查困难

如果从工程角度看,我觉得真正难的不是“更新成功”,而是:

  • 出错时能不能快速止损
  • 能不能知道到底哪一批机器生效了
  • 能不能证明当前实例拿到的是哪个版本

所以配置系统除了功能本身,可观测性也很关键。

5. 你做的优化是怎么证明有效的?

答案:

常见证明方式包括:

  • 压测对比:优化前后同样流量模型下的 QPS、RT、P99
  • 资源使用对比:CPU、内存、线程数、上下文切换
  • 线上监控对比:命中率、错误率、更新耗时、回滚次数
  • 热点路径 profile:看热点函数耗时是否下降
  • 异常场景验证:错误配置、重复发布、回滚时的表现是否稳定

比如如果我做了配置快照切换优化,我会重点看:

  • 读路径耗时是否下降
  • 更新生效耗时是否稳定
  • 更新过程中的请求失败率是否变化
  • CPU 和锁竞争是否下降

6. C++ 中为什么析构函数有时候必须写成虚函数

答案:当一个类会被当作基类使用,并且可能通过 基类指针删除派生类对象 时,析构函数必须是虚函数。否则通过基类指针 delete 派生类对象时,只会调用基类析构函数,派生类析构函数不会被正确执行,可能导致资源泄漏,属于未定义行为。

这本质上是因为:

  • 普通成员函数默认静态绑定
  • 析构过程如果不走虚函数机制,就无法根据对象真实类型完成完整析构链

代码:

#include <iostream>
using namespace std;

class Base {
public:
    virtual ~Base() {
        cout << "Base destroy" << endl;
    }
};

class Derived : public Base {
public:
    ~Derived() {
        cout << "Derived destroy" << endl;
    }
};

int main() {
    Base* p = new Derived();
    delete p;
    return 0;
}

7. std::move 一定会触发移动吗

答案:不一定。std::move 本身并不是“移动”,它只是把对象强制转换成右值引用,让编译器有机会匹配移动构造或移动赋值。最终会不会真的发生移动,要看:

  • 这个类型有没有实现移动构造/移动赋值
  • 移动操作是不是可用
  • 编译器有没有做拷贝省略
  • 某些情况下是否退化为拷贝

举例来说:

  • 如果类型没有移动构造,std::move 后还是可能调用拷贝构造
  • 如果对象是 const,通常也很难真正移动资源
  • 有些返回值场景下,编译器可能直接做 RVO/NRVO,连移动都省了

代码:

#include <iostream>
#include <utility>
using namespace std;

class Test {
public:
    

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

C++ 常考面试题总结 文章被收录于专栏

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

全部评论

相关推荐

03-08 16:30
门头沟学院 Java
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

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