腾讯 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.&nbsp;DDD演进了三层架构presatition-Application层(也可以叫service层、逻辑业务层BLL层)-DAL层(也可以叫Infra等),由于application层逻辑过多,后期维护容易像面条一样缠在一起,数据耦合混乱,引入DDD层&nbsp;依赖反转将数据流清晰,开发熵增慢。对于这一层的设计,将外部所有依赖都反转依赖DDD层,对层的设计,延伸出来了很多概念,entity-value&nbsp;object-domain&nbsp;service,用来定义DDD层的零件;aggregate-factory-repository用来规范对象的增(factory)删改查(aggregate)与持久化(repository)。2.架构通过文件系统(文件夹、命名)以模块化的形式展现,对应到具体的实践,DDD层以domain文件夹声明,domainService以命名*Manager声明等。2.业务演进模型会变得更加复杂、为了将层与层、模型与模型之间(拆分出界限)之间进行区分,又引入了限界上下文-上下文映射-域等概念;层与层之间需要通信,通过共享内核(shared)、防腐层(ACL)等进行通信。4.架构有很多书籍、很多架构形状,本质都在说同一件事情:引用《整洁架构的》观点,基于多态实现抽象接口,实践依赖反转的原则,忽略外部细节。5.架构设计-架构模式-设计模式,维度层层变小。DDD、整洁架构等一类思想启蒙类、内在审美类的书籍归类架构设计;微服务-六边形等属于具体的架构模式,是对思想和设计的实现;设计模式指的是GoF&nbsp;23种设计模式又是具体架构模式的局部细节抽象,维度就更低了。
点赞 评论 收藏
分享
评论
2
15
分享

创作者周榜

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