天津市网站建设_网站建设公司_博客网站_seo优化
2026/1/13 21:15:19 网站建设 项目流程

原文地址:腾讯校招 C++ 一面:30道题

最近有位粉丝朋友参加了腾讯C++岗位的面试,面试官提出了30道技术问题,涵盖了C++基础、网络编程、多线程、Web服务等多个方面。

我们来看一下腾讯校招的一面面经(30道题),希望能为大家提供参考。

如果你也准备冲击大厂,一定要做足了准备,大厂面试,要是没通过的话还会有记录,后面还想再去面就难咯。

更多大厂面试题: 字节跳动2面:为了性能,你会牺牲数据库三范式吗?

字节C++一面:enum和enum class的区别?

C/C++ 高频八股文面试题1000题(三)

直面米哈游C++面试:头文件“套娃”了咋整?

B站 C++ 一面:互斥锁和自旋锁的区别,使用场景分别是什么?

快手C++二面:static_assert底层原理解析

Q1自我介绍

面试官好,我是XXX,来自XX大学计算机专业大四学生。我有两年多的C++开发经验,熟悉C++11/14新特性,对底层原理有深入研究。在校期间,我主导开发了两个项目:一个基于倒排索引的搜索引擎和一个基于HTML5 Canvas的在线画图板。我热衷于解决技术难题,对性能优化有浓厚兴趣,希望能加入腾讯,与优秀的团队一起成长。

Q2你对虚函数是怎么理解的?

虚函数是C++实现多态的核心机制。当类中声明了虚函数,编译器会为该类生成虚函数表(vtable),其中存放了指向虚函数实现的指针。当通过基类指针或引用调用虚函数时,会根据对象的实际类型,在运行时动态绑定到正确的函数实现。

虚函数的实现原理是:每个包含虚函数的类对象都有一个隐藏的指针(vptr),指向该类的虚函数表。当调用虚函数时,通过vptr找到虚函数表,再找到对应的函数地址进行调用。

关键点:

  • 实现运行时多态
  • 需要基类指针或引用调用
  • 不能是静态成员函数
  • 析构函数最好声明为虚函数

Q3详细讲 static 关键字吧

static 在 C++ 中用法多样,核心是改变变量 / 函数的生命周期、作用域或链接属性:

静态局部变量:在函数内部声明的static变量,只初始化一次,生命周期贯穿整个程序运行期间。

void func() { static int count = 0; count++; std::cout << count << std::endl; }

静态全局变量:在全局作用域声明的static变量,作用域限制在当前文件内,避免命名冲突。

静态成员变量:类中声明的static成员变量,属于类而非类的实例,所有实例共享。

class MyClass { public: static int count; }; int MyClass::count = 0;

静态成员函数:类中声明的static成员函数,不能访问非静态成员,只能访问静态成员。

class MyClass { public: static void printCount() { std::cout << count << std::endl; } };

静态类:在匿名命名空间中定义的类,作用域限制在当前文件内。

Q4引用和指针有什么区别?

引用更安全,适合作为函数参数 / 返回值(避免拷贝);指针更灵活,适合动态内存管理、链表等场景。

特性

引用

指针

初始化

必须初始化,不能重新绑定

可以不初始化,可以重新指向

空值

不能为NULL

可以为NULL

语法

无需解引用,直接使用

需要使用*和->操作符

内存

无独立内存地址

有自己的内存地址

传递

值传递的别名

地址传递

Q5new 和 malloc 有什么区别?

特性

new

malloc

类型

C++操作符

C标准库函数

初始化

调用构造函数

不初始化内存

返回类型

指定类型指针

void*指针

错误处理

抛出std::bad_alloc异常

返回NULL

内存释放

delete

free

Q6说说C++11 的新特性?右值引用的应用场景?

C++11新特性:

  • auto类型推导
  • lambda表达式
  • 右值引用(移动语义)
  • 智能指针(unique_ptr, shared_ptr)
  • decltype
  • 范围for循环
  • 线程支持

右值引用应用场景:右值引用实现移动语义,避免不必要的拷贝,典型场景:

1、移动语义:当对象为右值(如临时对象)时,通过移动构造函数 / 移动赋值运算符 “窃取” 其资源(如堆内存),避免深拷贝,提升性能。

string a = "hello"; string b = move(a); // a的资源被转移到b,a变为空

2、完美转发:在模板函数中,通过 std::forward 保持参数的左值 / 右值属性,避免不必要的拷贝。

template <typename T> void func(T&& arg) { other_func(std::forward<T>(arg)); // 保持arg的原始属性 }

Q7C++是怎么做动态内存管理的?

    C++ 动态内存管理核心是手动控制与自动管理结合

    手动管理:new/delete(单个对象)、new []/delete [](数组),需手动配对使用,否则可能内存泄漏或崩溃。

    智能指针:推荐优先使用,自动管理内存生命周期:

    • unique_ptr:独占所有权,适合管理单个对象,不可拷贝但可移动;
    • shared_ptr:共享所有权,通过引用计数自动释放(计数为 0 时调用 delete);
    • weak_ptr:不增加引用计数,用于观察 shared_ptr 管理的对象,避免循环引用。

    内存池:针对频繁分配 / 释放小块内存的场景(如服务器高频请求),预先分配一大块内存,自行管理内存块分配与回收,减少系统调用和内存碎片。

    其他工具:allocator(STL 内存分配器接口)、boost.pool(第三方内存池库)等。

    Q8说一下 map 和 hashmap 的区别

    map(C++ 标准库中通常为 std::map)和 hashmap(非标准,通常指 std::unordered_map)的核心差异在底层实现与性能特性

    维度

    std::map

    std::unordered_map

    底层结构

    红黑树(平衡二叉搜索树)

    哈希表(数组 + 链表 / 红黑树)

    有序性

    键值自动排序(默认升序)

    无序

    查找效率

    O (log n)(树高)

    平均 O (1),最坏 O (n)(哈希冲突严重时)

    插入 / 删除

    O (log n)(树旋转调整)

    平均 O (1),需处理哈希冲突

    内存占用

    较低(仅存储键值对和树结构)

    较高(哈希表需要预留空间,避免冲突)

    键类型要求

    需支持 < 运算符(用于排序)

    需支持哈希函数(hash<Key>)和 == 运算符

    需要有序遍历或频繁范围查询用 map;追求极致查找 / 插入性能且键可哈希用 unordered_map。

    Q9讲一下堆和栈的区别吧

    堆(Heap)和栈(Stack)是程序运行时的两种内存区域,差异体现在分配方式、用途、特性

    维度

    栈(Stack)

    堆(Heap)

    分配方式

    编译器自动分配 / 释放(函数调用时入栈,返回时出栈)

    程序员手动分配 / 释放(new/malloc,delete/free)

    大小限制

    通常较小(默认几 MB,可通过编译器调整)

    较大(可达 GB 级,受系统内存限制)

    存储内容

    函数参数、局部变量、返回地址等

    动态分配的对象、数组等

    生长方向

    通常向下生长(高地址→低地址)

    通常向上生长(低地址→高地址)

    效率

    高(直接通过栈指针偏移操作)

    低(需查找空闲内存块,可能有碎片)

    安全性

    自动管理,不易泄漏但易栈溢出

    需手动管理,易泄漏或 double free

    Q10time_wait 是发生在哪一端?

    time_wait 是 TCP 四次挥手过程中的状态,发生在主动关闭连接的一端(通常是客户端)。

    • 当主动关闭方发送 FIN 报文,收到被动关闭方的 FIN+ACK 后,会进入 time_wait 状态,等待 2MSL(报文最大生存时间,通常为 1-2 分钟)。
    • 作用:确保被动关闭方收到最后的 ACK(避免 ACK 丢失导致被动方重发 FIN);防止已关闭的连接端口被复用后,接收旧连接的残留报文。

    Q11如果很多连接都是处于 time_wait 状态,该怎么处理?

    1、内核参数调整:

    • sysctl -w net.ipv4.tcp_tw_reuse=1
    • sysctl -w net.ipv4.tcp_tw_recycle=0# 已弃用
    • sysctl -w net.ipv4.tcp_fin_timeout=30

    2、优化程序:

    • 避免频繁创建/关闭短连接
    • 使用长连接(HTTP keep-alive)
    • 减少客户端连接数

    3、增加端口范围:

    sysctl -w net.ipv4.ip_local_port_range="1024 65535"

    Q12select 和 epoll 的区别?

    select 和 epoll 都是 Linux 下的 IO 多路复用机制,用于高效处理多文件描述符(FD)的 IO 事件,核心差异在性能与设计

    维度

    select

    epoll

    FD 数量限制

    有(默认 1024,受限于 FD_SETSIZE)

    无(仅受系统内存限制)

    效率

    O (n)(每次调用需轮询所有 FD)

    O (1)(通过回调机制,仅处理就绪 FD)

    数据结构

    基于位图(fd_set)

    基于红黑树(管理 FD)+ 就绪链表(存储就绪 FD)

    内存拷贝

    每次调用需将 fd_set 从用户态拷贝到内核态

    仅初始化时拷贝,后续通过共享内存访问

    触发方式

    仅水平触发(LT)

    支持水平触发(LT)和边缘触发(ET)

    总结:高并发场景下 epoll 性能远优于 select,是 Linux 高性能服务器的首选(如 Nginx、Redis)。

    Q13讲一下 LT 和 ET 有什么区别?

    • LT(Level Triggered):当文件描述符就绪时,epoll_wait会一直返回该事件,直到事件被处理。优点:编程简单(无需一次性处理完所有数据);缺点:可能导致重复通知,效率略低。
    • ET(Edge Triggered):只在文件描述符状态变化时触发一次事件。优点:减少通知次数,效率更高; 缺点:编程复杂(需一次性处理完所有数据,否则可能遗漏事件),必须使用非阻塞 IO。

    ET 模式需配合非阻塞 IO,适合高并发场景;LT 模式适合对编程复杂度敏感的场景。

    Q14讲一下 get 和 post 的区别?

    特性

    GET

    POST

    数据位置

    URL查询字符串

    请求体

    数据长度

    受URL长度限制(约2048字符)

    无限制

    安全性

    不安全(URL可见)

    相对安全(请求体不可见)

    幂等性

    用途

    获取数据

    提交数据

    Q15http2 和 http1 的区别?

      二进制协议:HTTP/1.x 是文本协议(易读但解析效率低),HTTP/2 是二进制帧(Header Frame 和 Data Frame),解析更快且错误少。

      多路复用:HTTP/1.x 中每个连接只能处理一个请求(需排队,即 “队头阻塞”);HTTP/2 允许一个连接同时处理多个请求(通过帧的 stream ID 区分),大幅提升并发效率。

      头部压缩:通过 HPACK 算法压缩请求头(HTTP/1.x 头部重复传输且未压缩),减少带宽消耗。

      服务器推送:服务器可主动向客户端推送关联资源(如 HTML 引用的 CSS/JS),无需客户端请求。

      流量控制:每个 stream 可独立进行流量控制,避免单个请求占用过多资源。

      Q16http 和 https 的区别?

      区别:HTTP是明文传输,HTTPS通过SSL/TLS加密传输。

      HTTPS优点

      • 数据加密,防止窃听
      • 身份验证,确保连接到正确服务器
      • 数据完整性,防止篡改

      HTTPS缺点

      • 需要SSL/TLS证书,增加成本
      • 加密解密增加CPU开销
      • 首次连接需要握手,增加延迟

      Q17什么时候要使用多线程编程?

        IO 密集型任务:如网络请求、文件读写等(IO 操作时线程会阻塞,多线程可让 CPU 处理其他任务)。例如:服务器同时处理多个客户端的请求。

        CPU 密集型任务:如大规模计算、数据处理等(多线程可利用多核 CPU 并行计算)。例如:图像渲染、矩阵运算。

        响应性要求高的场景:如 GUI 程序(主线程处理界面交互,子线程处理耗时操作,避免界面卡顿)。

        任务拆分场景:将复杂任务拆分为多个子任务,并行执行缩短总耗时。

        Q18多线程编程里面,你怎么理解互斥锁和自旋锁?

        互斥锁(Mutex)和自旋锁(Spinlock)都是用于保护临界区的同步机制,核心差异在阻塞策略:

        • 互斥锁(Mutex):当锁被占用时,线程会进入睡眠状态,等待锁释放。适合长时间持有锁的场景。优点:不占用 CPU 资源,适合临界区执行时间较长的场景; 缺点:上下文切换开销大(阻塞→唤醒涉及内核态操作)。
        • 自旋锁(Spinlock):当锁被占用时,线程会不断循环检查锁是否可用,不进入睡眠。适合锁持有时间很短的场景。优点:无上下文切换开销,适合临界区执行时间极短的场景; 缺点:自旋时占用 CPU,多核心场景下效率更高(单核心可能导致死锁)。

        选择依据

        • 锁持有时间短 → 自旋锁
        • 锁持有时间长 → 互斥锁


        Q19用 mysql 吗?

        是的,在项目中频繁使用 MySQL 作为关系型数据库,主要涉及:

        • 基础操作:通过 C++ 的 MySQL Connector 或封装的 ORM 库进行 CRUD(增删改查)操作;
        • 性能优化:设计合理的索引(如 B + 树索引)、优化 SQL 语句(避免 select *、冗余连接)、使用查询缓存(已在 8.0 移除,改为应用层缓存);
        • 事务与隔离级别:利用 InnoDB 引擎的 ACID 特性,根据场景选择隔离级别(如读已提交避免脏读);
        • 高可用:配合主从复制、读写分离提升并发能力,使用连接池(如 SQLiteConnectionPool)减少连接建立开销。

        Q20影响web服务性能的因素

        1. 网络:带宽、延迟、网络拥塞
        2. 服务器硬件:CPU、内存、磁盘I/O
        3. 代码效率:算法复杂度、内存管理
        4. 数据库:查询优化、索引、连接池
        5. 并发模型:I/O多路复用、线程池
        6. 缓存:是否使用Redis等缓存
        7. HTTP/HTTPS:是否使用HTTP/2,SSL/TLS开销

        Q21怎么提升服务器的并发性能?

        1. I/O多路复用:使用epoll、kqueue等
        2. 线程池:限制并发线程数
        3. 异步编程:使用libevent、boost.asio
        4. 缓存:使用Redis缓存热点数据
        5. 数据库优化:索引优化、连接池
        6. 负载均衡:多台服务器分担流量

        Q22刚提到线程池,内部的线程一般是多少个?

        线程池线程数量根据任务类型确定:

        • CPU密集型:线程数 = CPU核心数 + 1
        • IO密集型:线程数 = CPU核心数 × 2 + 1

        例如,4核CPU:

        • CPU密集型:5个线程
        • IO密集型:9个线程

        实际应用中需动态调整,例如:通过监控 CPU 利用率和任务队列长度,动态增删线程(弹性线程池)。常见经验值:8 核 CPU 处理 IO 密集型任务时,线程数可设为 16-40。

        Q23倘若你用了线程池,但是高峰时期流量就是太高了,服务器承受不住,你该怎么办?

        1. 水平扩展:增加服务器数量,通过负载均衡分担流量
        2. 限流:在入口处设置限流(如令牌桶算法)
        3. 降级:关闭非核心功能,保证核心功能可用
        4. 异步队列:将请求放入消息队列(如Kafka、RabbitMQ)

        Q24倘若就算这样还是不行,怎么办?

        1. 代码优化:分析性能瓶颈,优化关键路径
        2. 缓存:增加缓存层,减少数据库压力
        3. CDN:使用CDN分发静态资源
        4. 预热:提前加载热点数据,减少高峰期计算

        Q25倘若你就只有一台服务器,没有更多的硬件资源了,怎么办?

        1. 优化代码:深入分析性能瓶颈
        2. 减少依赖:移除不必要的功能
        3. 调整系统参数:优化文件描述符、TCP参数
        4. 使用高效内存分配:如jemalloc替代malloc
        5. 数据压缩:减少网络传输量

        Q26倘若你的操作无法用原子性,一个线程不断的生产任务,放到队列中,另一个从队列中拿取请求,如何做到无锁编程?

        使用CAS(Compare-And-Swap)实现无锁队列:

        template <typename T> class LockFreeQueue { private: struct Node { T data; std::atomic<Node*> next; Node(T d) : data(d), next(nullptr) {} }; std::atomic<Node*> head; std::atomic<Node*> tail; public: void push(T data) { Node* new_node = new Node(data); Node* old_tail = tail.load(); while (true) { Node* next = old_tail->next.load(); if (old_tail == tail.load()) { if (next == nullptr) { if (old_tail->next.compare_exchange_strong(next, new_node)) { tail.compare_exchange_strong(old_tail, new_node); return; } } else { tail.compare_exchange_strong(old_tail, next); } } } } bool pop(T& data) { Node* old_head = head.load(); while (true) { Node* next = old_head->next.load(); if (old_head == head.load()) { if (next == nullptr) { return false; } if (head.compare_exchange_strong(old_head, next)) { data = next->data; delete old_head; return true; } } } } };

        Q27平常有什么兴趣爱好?

        编程方面平时喜欢深入研究 C++ 标准和 Linux 内核源码(如 STL 容器实现、epoll 原理),尝试用 C++ 实现一些基础组件(如线程池、内存池)。阅读技术博客(如 CppCon 演讲、Linux 内核月报),偶尔做一些算法题(LeetCode 中等难度)保持思维活跃度。生活方面,喜欢打篮球和跑步,保持身体健康。

        Q28最近有看什么技术书籍吗?

        最近在读《深入理解计算机系统》(CSAPP),这本书从底层到应用层详细讲解了计算机系统,对理解操作系统、编译器、网络等有帮助。也读了《C++并发编程实战》,对多线程编程有了更深的理解。

        Q29你写的两个项目,搜索引擎和在线画图板,是你的课程设计吗?

        不是课程设计,是自主开发的项目。搜索引擎主要用于学习倒排索引、分词算法和分布式爬虫;在线画图板则是为了实践实时数据同步(基于 WebSocket)和分布式锁(Redis 实现),两个项目均部署在云服务器上,可通过公网访问,源码已开源到 GitHub。

        Q30你的 httpserver 是怎么搭建的?

        基于 C++11 实现,核心架构如下:

        网络层:

        • 用 socket 创建 TCP 监听端口,通过 epoll 实现 IO 多路复用(LT 模式);
        • 支持 TCP 长连接,通过心跳包检测连接状态。

        协议层:

        • 解析 HTTP 请求(method、uri、headers、body),支持 GET/POST 方法;
        • 构建 HTTP 响应(状态码、响应头、响应体),支持 gzip 压缩。

        并发处理:

        • 主线程负责 accept 新连接和 IO 事件分发;
        • 工作线程池(线程数 = CPU 核心数 * 2)处理请求逻辑(路由匹配、业务计算)。

        路由与业务:

        • 用 std::unordered_map 存储路由表(uri→处理函数);
        • 支持静态资源(html/css/js)访问和动态接口(如 /search)。

        扩展:

        • 集成 OpenSSL 实现 HTTPS(配置证书和私钥);
        • 加入简单的访问控制(IP 黑名单)和请求限流。

        通过压测工具(如 wrk)优化,单服务器可支持每秒数千 QPS(取决于请求类型)。

        需要专业的网站建设服务?

        联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

        立即咨询