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

1. 自我介绍

2. 实习项目拷打

3. shared_ptr 性能优于 unique_ptr 吗,为什么

答案:一般来说不能这么说,绝大多数场景下 unique_ptrshared_ptr 更轻量。unique_ptr 只有独占所有权,不需要维护引用计数,大小通常就是一个裸指针,移动也只是转移所有权。shared_ptr 需要额外的控制块来维护强引用和弱引用计数,多线程下还涉及原子操作,所以构造、拷贝、销毁成本都更高。只有在确实需要共享所有权的时候,shared_ptr 才有意义,而不是因为它“更高级”就优先使用。如果面试官继续追问,通常会往控制块、循环引用和 make_shared 上延伸。

4. make_shared 和直接 new 再构造 shared_ptr 有什么区别

答案:make_shared<T>() 一般会把对象本体和控制块放在一次内存分配里完成,分配次数更少,局部性更好,也更不容易因为中间步骤异常导致资源泄漏。而 shared_ptr<T>(new T(...)) 通常至少涉及对象本体和控制块两次分配。但 make_shared 也不是所有场景都适合,比如如果对象很大,而又有很多 weak_ptr 长时间存在,那么对象本体虽然已经析构,控制块还在,整体内存回收时机会更靠后。所以这题真正要答的是原理差异,而不是死记“哪个更好”。

代码:

#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 直接传会编译不过;另一个是如果异步任务执行时机不确定,就要非常清楚资源所有权已经不在原线程手里,不能再继续访问。比较常见的处理方式是用 std::moveunique_ptr 捕获到 lambda 里,或者让线程池支持完美转发,把任务参数原样转进工作队列。如果资源本来就需要跨多个任务共享,那就不该硬用 unique_ptr,而要重新设计所有权模型。

代码:

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

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

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

    t.join();
    return 0;
}

6. shared_ptr 的控制块里一般有什么

答案:控制块一般会保存强引用计数、弱引用计数、删除器、分配器,有些实现还会带类型擦除后的销毁逻辑。多个 shared_ptr 指向同一对象时,共享的是这个控制块,而不是彼此复制一份状态。当强引用计数减到 0 时,对象本体被释放;当强弱引用都减到 0 时,控制块自身才会被释放。如果答得再深入一点,还可以讲 enable_shared_from_this 为什么必须和同一控制块关联,否则会出未定义行为。

7. C++ 新特性你常用哪些,STL 用过哪些

答案:常用的新特性一般有 auto、范围 for、右值引用、移动语义、nullptrlambdathreadmutexcondition_variableatomicunique_ptrshared_ptrunordered_mapconstexpr。STL 里常用的容器主要是 vectordequelistmapunordered_mapsetpriority_queue,算法里常用 sortfindlower_boundbinary_search。面试里这题最好不要报菜名式回答,通常挑几个自己真正用得多的展开,比如为什么 vector 常用、unordered_map 什么时候比 map 更合适、emplace_backpush_back 的差别。

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

答案:lambda 本质上会被编译器生成一个匿名的闭包类型,对捕获的外部变量作为成员保存,再重载 operator()。仿函数则是开发者手写的一个类或结构体,同样通过重载 operator() 来表现得像函数。所以从本质上讲,lambda 可以看成是一种编译器帮你生成的仿函数,只不过语法更轻便,更适合局部短逻辑。如果需要复用、需要显式命名类型、需要模板参数化或者更复杂的状态管理,仿函数会更合适;如果只是回调、谓词、局部处理逻辑,lambda 更方便。

代码:

#include <iostream>
using namespace std;

struct Add {
    int operator()(int a, int b) const {
        return a + b;
    }
};

int main() {
    auto lam = [](int a, int b) { return a + b; };
    Add add;
    cout << lam(1, 2) << endl;
    cout << add(3, 4) << endl;
    return 0;
}

9. lambda 捕获 [=][&][this] 时要注意什么

答案:这题在客户端和异步代码里很常见。[=] 是值捕获,默认把用到的外部变量拷贝进闭包对象;[&] 是引用捕获,闭包里保存的是外部变量引用;[this] 则是捕获当前对象指针。真正危险的地方在于异步执行场景,比如把 lambda 投递到线程池、定时器或者 Qt 事件循环里,如果你捕获的是引用或 this,而执行时原对象已经析构,就很容易出现悬空引用。所以这题回答最好带上生命周期意识,特别是在 UI 编程和多线程场景里。

10. Qt 信号槽机制底层怎么实现

答案:Qt 的信号槽依赖元对象系统。类里加了 Q_OBJECT之后,MOC 会生成额外代码,把

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

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

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

全部评论

相关推荐

昨天 13:58
已编辑
哈尔滨工业大学 Java
有见过上来就写一个完整的线程池的吗?面试官一张嘴我差点尿了Q1:前面两个面试官已经提问了项目,咱们直接写一道题吧,线程池,不会c++可以用你会的语言。。。。PS:shit30min&nbsp;later。。。Q2:java21中的虚拟线程应用到你的项目中会有什么变化?PS:holy&nbsp;shit,前面java21没听清,就听到个虚拟线程,我没听这个概念,我人都傻了A:sorry面试官,我没有思考过这个问题。。。Q3:如果Redis的Pub/Sub因为某些原因没有传递到,你的caffeine会不会被读取到过期数据A:设计了很短的过期时间&nbsp;+&nbsp;引入消息队列重试机制Q4:如果Redission分布式锁的持有者宕机,看门狗没有续期,10000个QPS会全部达到DB上吗A:不会,因为锁无人持有,会有一个线程抢到锁,其他线程阻塞,等待会写,所以只有一个线程能到DB。PS:不知道为啥我说完又问了我一遍,感觉没说错啊,我就说的更详细了一点。。Q5:你试用Canal监听binlog实现ES和MySQL的一致性,如果Canal因为MySQL的Update太多导致Canal同步跟不上怎么办A:只想到了把Canal监听binlog的方式改为row,加速读取,然后对MySQL进行取舍(因为我问了下,MySQL主从是否一致,面试官说可能不一致),因为MYSQL主从同步有四个策略,当选择超半数同意才接受的方案时,如果Update操作太多,那么直接拒绝。还有考虑数据库分库分表,分担压力,避免所有更新请求打到少数数据库上。只想到这么多,前者回答的肯定不够,但是对Canal了解不多,没招了Q6:了解aqs吗,怎么实现一个ReentrantlockA:内部类继承aqs,针对state,队列进行设计实现公平锁或非公平锁,重写tryAccique和tryRelease,对外暴露接口Q7:你项目几个人做的,都是实验室项目吗?Q8:反问环节A:多久出结果,核心业务是什么,还有技术面吗?PS:一周内出结果,后面是hr面,业务关于支付等等没注意听,实习两个月之后有技术面本牛子0实习,bg:29,希望能通过吧。这是最后一个面试了,前面全挂了,牛友们可以看看我的其他帖子,分享了一些比较难的面经,真难绷
查看6道真题和解析
点赞 评论 收藏
分享
评论
1
4
分享

创作者周榜

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