腾讯 WXG客户端开发-C++ 一面

1. 自我介绍

2. 讲一下你做过的项目,重点说说一个最有挑战的点

3. shared_ptr 性能优于 unique_ptr 的原因是什么

答案:严格来说,这个说法通常是不成立的。unique_ptr 一般比 shared_ptr 更轻,因为它只有独占所有权,不需要维护引用计数,也没有额外控制块的原子增减开销。shared_ptr 的优势不是“更快”,而是适合共享所有权场景,多个对象都需要安全持有同一资源时,它能减少手动管理生命周期带来的错误。所以如果对象所有权天然唯一,优先用 unique_ptr;只有当共享所有权确实是业务需要时,才考虑 shared_ptr。面试里如果对方故意这么问,比较好的答法是先纠正前提,再说明两者适用场景。

4. make_shared 和直接用 shared_ptr(new T) 有什么区别

答案:make_shared<T>() 通常会把对象和控制块一次性分配在一块连续内存里,而 shared_ptr<T>(new T) 往往是对象和控制块分开分配。这样 make_shared 一般分配次数更少、缓存局部性更好,也更不容易在“先 new 成功、后构造 shared_ptr 失败”这种边界情况下泄漏。不过它也不是总是最优。比如对象很大、生命周期复杂,或者你需要自定义删除器、需要和某些底层 API 配合时,直接构造 shared_ptr 可能更灵活。还有一点常被问到:如果外部还有 weak_ptr 悬挂着,make_shared 那块整体内存可能要等控制块一起释放,而分离分配时对象本体和控制块的回收时机更容易区分。

代码:

#include <memory>
using namespace std;

struct A {
    int x;
    A(int v) : x(v) {}
};

int main() {
    auto p1 = make_shared<A>(10);
    shared_ptr<A> p2(new A(20));
    return 0;
}

5. unique_ptr 怎么在线程池里传参,会有什么问题,怎么解决

答案:unique_ptr 不能拷贝,只能移动,所以在线程池里传参时要特别注意任务提交接口是不是按值拷贝捕获。如果你直接把 unique_ptr 当普通参数传给需要拷贝可调用对象的线程池,很可能会编译不过,或者被错误设计逼着改成裸指针,那就会引入生命周期风险。通常有几种处理方式:一种是任务提交时用移动捕获,把 unique_ptr 所有权转进任务对象;另一种是如果确实需要多个执行单元共享,就改成 shared_ptr;再一种是在线程池任务队列内部支持 move-only callable。本质问题不在 unique_ptr,而在线程池接口设计是否支持只移动不可拷贝的任务。

代码:

#include <iostream>
#include <memory>
#include <thread>
using namespace std;

int main() {
    unique_ptr<int> p = make_unique<int>(42);

    thread t([q = std::move(p)]() mutable {
        cout << *q << endl;
    });

    t.join();
    return 0;
}

6. C++ 新特性你比较常用哪些,STL 常用组件有哪些

答案:我比较常用的是 C++11 之后这几类能力:右值引用和移动语义、auto、范围 for、智能指针、lambdaconstexprthreadatomicoptionalvariantstring_view,再往新一点会用到结构化绑定、if constexprspan 之类的。STL 里最常用的是 vectorstringunordered_mapmapsetqueuepriority_queuefunctiontuple、算法库以及并发相关组件。真正工程里我会比较在意容器选择背后的语义,比如是否需要稳定地址、是否需要有序、是否需要高频插删、是否容易触发 rehash。所以这题不只是背 API,更重要的是你是否知道这些特性能解决什么问题。

7. lambda 和仿函数有什么区别

答案:lambda 本质上会被编译器生成为一个匿名的函数对象类型,也就是匿名仿函数。两者都可以持有状态,也都能重载调用运算符 operator()。区别主要在表达方式和可控性上:lambda 写起来更短,适合局部逻辑;显式仿函数类型更适合需要复用、需要模板特化、需要写多个重载版本或者对对象布局有控制的场景。另外无捕获 lambda 可以退化成函数指针,有捕获 lambda 不行;仿函数类型则始终是一个明确的类类型。

代码:

#include <iostream>
using namespace std;

struct Add {
    int base;
    Add(int x) : base(x) {}
    int operator()(int y) const { return base + y; }
};

int main() {
    auto lam = [x = 10](int y) { return x + y; };
    Add functor(10);

    cout << lam(5) << endl;
    cout << functor(5) << endl;
    return 0;

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

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

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

全部评论

相关推荐

评论
1
1
分享

创作者周榜

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