c++面试八股文2
1、其他方面
- 自我介绍
- 过往的项目介绍,追问了一些细节问题
- 谈谈你印象较深的项目
- 说一件你做过最棘手的事,并谈谈你是怎么解决的,有什么经验分享
- 平时看C++的书有哪些
- 之前项目里团队合作怎么样,举例子说明
- 为什么想来我们公司
- 你的最大优势是什么
- 你觉得哪些特质符合我们岗位
- 有没有其他在谈的offer
2、反问环节
3、薪资预期
4、内存分区讲一下(C++内存分配的方式有几种)
栈:适合小对象和短生命周期变量,自动管理。 堆:适合大对象和需要跨函数使用的变量,需手动管理。 全局 / 静态区:适合贯穿整个程序生命周期的变量。 常量区:存放不可修改的常量数据。 代码区:存储程序执行指令。
5、c语言多态和原理
在 C 语言中实现多态(Polymorphism)需要通过函数指针和结构体来模拟,因为 C 语言本身不支持面向对象编程中的虚函数和继承机制。
通过函数指针实现回调机制,在运行时动态选择执行的函数。 将一组相关函数存储在一个表中,通过索引或标签查找并调用对应函数。
C++ 多态的核心机制是虚函数表(VTable) 和虚表指针(VPTR),其关键点包括:
- 动态绑定:通过虚函数表在运行时确定调用的函数。
- 虚析构函数:确保通过基类指针删除派生类对象时资源正确释放。
- 多重继承:每个基类有独立的虚函数表,需处理指针偏移。
- 抽象类:通过纯虚函数定义接口,强制派生类实现。
6、静态成员函数访问非静态数据成员的方法
最常见的方法:通过传递对象指针或引用作为参数,间接访问非静态成员。 如果类的所有对象共享同一个状态,可以使用全局变量或单例模式。
7、三次握手四次挥手
8、I0多路复用是否了解(IO模型)
epoll的底层原理
9、多线程的锁,读写锁的特点
10、分布式
11、socket编程了解多少
12、C++中的虚函数和纯虚函数有什么区别,使用场景
纯虚函数和虚函数必须在派生类中实现吗 说说抽象类
13、C++的内联函数,和普通函数有什么区别
内联函数适用于短小的函数体,频繁调用的情况,以减小函数调用的开销。 普通函数适用于复杂的函数体,不经常调用的函数,或者需要在不同的源文件中共享的函数。 内联函数的调用处会被编译器尽量替换为函数体的实际代码,而普通函数会产生实际的函数调用开销。
14、C++指针和引用的区别
15、指针常量和常量指针的区别
指向常量的指针,简称常量指针。 指针常量必须在声明的同时对其初始化,不允许先声明一个指针常量随后再对其赋值,这和声明一般的常量是一样的。
16、智能指针
17、线程(问为什么使用的是Linux下的pthread_create而不是使用c++本身的函数)
18、哈希表的原理,解决哈希冲突
19、怎么实现线程池,有什么需要注意的
线程池(Thread Pool)是一种管理和复用线程的技术,通过预先创建一组线程并重复使用它们来执行任务,避免了频繁创建和销毁线程的开销。
线程池的核心组件
- 任务队列(Task Queue):存储待执行的任务。
- 工作线程(Worker Threads):从任务队列中取出任务并执行。
- 管理者线程(Manager Thread):监控线程池状态,动态调整线程数量(可选)。
- 线程同步机制:保证任务队列的线程安全。
20、线程安全
在多线程编程中,线程安全(Thread Safety) 是一个至关重要的概念,它确保多个线程同时访问共享资源时不会导致数据竞争(Data Race)、不一致或程序崩溃。 当一个函数、类或程序在多线程环境中能够正确处理并发访问,而无需调用方额外同步时,它被称为线程安全。
21、保证线程安全的方法
方法 适用场景 性能开销 复杂度 互斥锁 复杂操作的原子性保护 高 中 原子操作 简单计数器、标志位 低 低 读写锁 读多写少的场景 中 中 线程本地存储 避免共享状态 低 低 不可变对象 频繁读取、很少修改的数据 低 低 无锁数据结构 高并发队列、栈等 极低 高
22、volatile关键字的作用
C++ 的 volatile 主要用于告诉编译器 “变量可能被意外修改”(如硬件寄存器),不直接保证线程安全。
23、堆栈的区别
malloc和new的区别
特性 malloc new 构造 / 析构函数 不调用 自动调用 类型安全性 需手动转换 void* 自动推导类型 内存分配失败 返回 nullptr 默认抛异常,可指定返回 nullptr 重载能力 无法重载 支持全局和类级重载 数组处理 无特殊支持 需使用 new[] 和 delete[] 适用场景 C 风格内存管理、原始内存操作 C++ 对象管理、RAII 机制
24、左值引用和右值引用
左值(lvalue): 可以出现在赋值语句左侧的表达式,通常拥有持久的内存地址。你可以对它取地址。比如,变量名、数组元素等。
右值(rvalue): 只能出现在赋值语句右侧的表达式,通常是临时的、即将消亡的值。你不能对它取地址。比如,字面量(42, true)、函数返回的临时对象等。
C++11引入了右值引用(Rvalue Reference),用 && 表示,专门用于“绑定”右值。它的主要目的是实现移动语义(Move Semantics),通过“窃取”临时对象的资源来避免不必要的深拷贝,从而极大地提升性能。
25、STL中迭代器失效的情况有哪些?
插入和删除操作
26、完美转发
参考:https://mp.weixin.qq.com/s/CKJvlDjzgh5PoHDheZmeRg
现在,想象一个场景:你需要编写一个通用的工厂函数 factory,它接收任意类型的参数,然后将这些参数传递给构造函数来创建一个对象。
template<typename T, typename Arg>
T* factory(Arg arg) {
return new T(arg);
}这个简单的实现会遇到什么问题? 传入右值:factory<MyClass>(MyClass())。这里 MyClass() 是一个右值,但当它在 factory 函数内部被传递给 T 的构造函数时,参数 arg 本身是一个有名字的变量,因此它是一个左值!我们丢失了原始参数是右值这一重要信息,导致本可以发生的移动构造变成了拷贝构造。
传入左值:MyClass obj; factory<MyClass>(obj);。这里 arg 是 obj 的一个拷贝,如果 Arg 的拷贝构造代价很高,性能会劣化。我们更希望传递引用。
万能引用 (Universal Reference)
当你看到 T&& 这样的语法时,你的第一反应可能是“右值引用”。但这不完全正确。在模板参数推导的上下文中,T&& 有一个特殊的名字——万能引用(Scott Meyers提出的术语),现在更被官方地称为转发引用(Forwarding Reference)。
它既能绑定左值,也能绑定右值,取决于传入参数的类型: 如果传入一个左值A,模板参数 T 被推导为 A&。 如果传入一个右值A,模板参数 T 被推导为 A。
引用折叠 (Reference Collapsing)
C++语法不允许直接声明“引用的引用”,比如 int& & x; 是非法的。但在模板实例化过程中,这种结构会间接出现。引用折叠规则定义了如何将这种“引用的引用”简化为单个引用: A& & -> A& (左值引用的左值引用 -> 左值引用) A& && -> A& (左值引用的右值引用 -> 左值引用) A&& & -> A& (右值引用的左值引用 -> 左值引用) A&& && -> A&& (右值引用的右值引用 -> 右值引用) 核心规则:只要有&(左值引用)出现,最终结果就是&。只有当所有引用都是&&(右值引用)时,结果才是&&。
std::forward 的魔法:std::forward<T>(arg)
变参模板
内存屏障
在多线程编程中,内存屏障(Memory Barrier) 是一种同步原语,用于控制内存操作的顺序和可见性。它解决了编译器优化、CPU 指令重排和缓存一致性带来的问题,确保代码在多线程环境下的正确性。
std::thread_local
Linux内核
一、内核架构与核心组件
- 整体架构 单内核(Monolithic Kernel):所有核心功能集成在一个二进制文件中,性能高但复杂度高。 模块化设计:支持动态加载 / 卸载内核模块(如驱动程序)。
- 核心组件 进程调度器:管理 CPU 资源,实现多任务处理。 内存管理器:虚拟内存管理、页面置换、内存分配。 文件系统:支持多种文件系统(ext4、XFS、Btrfs 等)。 设备驱动:硬件抽象层,控制外设(网卡、硬盘、显卡等)。 网络协议栈:实现 TCP/IP、UDP 等网络协议。 系统调用接口:用户空间与内核空间的桥梁。 二、内核空间 vs 用户空间 用户空间: 应用程序运行的区域,权限受限。 通过系统调用(如read()、write())访问内核功能。 内核空间: 内核代码运行的特权区域,可直接访问硬件。 发生系统调用或中断时,CPU 从用户态切换到内核态。
docker
reactor
在计算机编程领域,Reactor 模式 是一种事件驱动的设计模式,常用于构建高性能网络服务器和事件处理系统。它通过将 I/O 事件的检测和处理分离,实现高效的并发处理。
IO模型
IO 模型 优点 缺点 适用场景 同步阻塞 IO 实现简单,逻辑清晰 线程开销大,并发能力低 连接数少且 IO 耗时短的场景 同步非阻塞 IO 单线程处理多连接 轮询消耗 CPU,效率低 连接数多但 IO 频繁的场景 IO 多路复用(select/poll) 高效处理大量连接 FD 数量限制(select),线性扫描就绪 FD 中大规模并发场景 IO 多路复用(epoll) 高性能,事件通知机制 仅 Linux 支持 大规模高并发场景(如 Nginx) 异步 IO 真正异步,线程利用率极高 依赖操作系统,实现复杂 IO 密集型、长耗时操作的场景
对线程池有了解吗,介绍一下
内存池
在 C++ 中,内存池(Memory Pool) 是一种内存管理技术,用于优化频繁分配和释放小块内存时的性能问题。它通过预先分配大块内存并自行管理内存分配,减少系统调用开销和内存碎片。
对象池
在软件开发中,对象池(Object Pool) 是一种创建和管理对象的设计模式,旨在通过复用已创建的对象来提高性能和资源利用率。它尤其适用于创建成本高、使用频率高的对象(如数据库连接、线程、网络套接字等)。
说一下你知道的排序算法的时间复杂度和空间复杂度
知道哪些c++11新特性
- 自动类型推导(auto)
- 范围 - based for 循环
- 智能指针(Smart Pointers)
- Lambda 表达式
- 右值引用与移动语义
虚函数的作用?
子类重写,实现多态
迭代器是指针吗?
参考:https://zhuanlan.zhihu.com/p/470874027 迭代器不是指针,而是类模板。它封装了指针并重载指针的一些运算符,如++,--,等,所以能够遍历部分或全部访问容器元素的对象。迭代器返回的是对象的引用,所以不能直接访问,需要用解引用再访问。
讲一下capacity(), size(), reserve(), resize() 函数的区别。
size()用于返回容器当前的元素个数。而capacity()返回容器的容量。
reserve()是为容器预留空间,改变的是capacity,size保持不变。
resize()既改变了capacity,又改变了size。
reserve(x), 只有x>capacity才有用。
resize(x,val),1. x > capacity,那么会在原容器内补充x-capacity个值为val的元素;2. x <= capacity,那么容器内前x个元素值变为为val,其余不变
什么是仿函数?
仿函数(Functor)又称为函数对象(Function Object)是一个能行使函数功能的类。
仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载 operator() 运算符。因为调用仿函数,实际上就是通过类对象调用重载后的 operator() 运算符。
auto 和 decltype 区别。
auto可以自动类型推导,但无法定义变量类型,可以用于返回值和形参。
decltype返回变量类型,和auto一样在编译器起作用 。大部分情况下auto更好用一些,但是在比如一些容器的比较函数上,只能用decltype。
auto不能用于含有递归的匿名函数。
C++中override关键字的作用构造函数是否可以是虚函数(解释原因)?虚函数是否可以使用static关键字?C++内存中堆和栈的区别为什么栈的效率比堆高?介绍二叉搜索树,平衡二叉树(左旋右旋操作),红黑树 虚函数表的机制构造函数可以是虚函数嘛说出原因C++11新特性介绍三种智能指针weak_ptr如何访问指向的数据右值引用将亡值有哪些new出来的数据存放在哪里多线程的模式介绍项目中用到的生产者消费者模式生产者生产太快,消费者消费太慢怎么办(条件变量)负载均衡算法有哪些(只答了概念,没具体了解有哪些算法)介绍thrift框架介绍rpc框架介绍项目中的raft协议发生网络故障时raft协议如何工作的tcp和udp的区别介绍websocket介绍redis,为什么redis快?redis的两种落盘方式?redis如何做分布式?(不会)决策树节点分裂的算法?在腾讯实习的大语言模型用的哪些?会Python嘛,是否用过pandas之类的库,平时如何学Python 的leetcode23.合并k个升序链表(用优先队列秒了)反问,面试官说主要用c++和python的,同时给了建议可以学一学c++服务端开发方向的内容。 科大讯飞(C++软件开发,一面)作者:@Dijkstra1 自我介绍 项目流程相关,面试官挺感兴趣的,就这个聊了很多 以下是穿插的一些八股: TCP、UDP的选择 可靠传输机制 HTTP的了解程度 多线程、多进程 文件IO,了解一些文件存储的方案吗 共享资源,同步互斥、使用场景 科大讯飞(C++软件开发,二面)作者:@Dijkstra1 自我介绍 聊聊对AI技术的理解 生活中的AI 怎么学习AI相关的 最近有看的AI方面的论文 有什么好的学习习惯能分享一下吗 平常和朋友怎么看待AI的 成绩还行,获得过什么奖吗 有参与过开源项目吗 有过大型服务器的经历吗(怎么突然从AI转服务器了) 接上问,能分享一下遇到过的坑及怎么解决的吗 看你是学C++的,问点编程内容吧 多线程死锁了怎么排查 怎么优化一个程序,更高效的执行 比如循环如何更高效的执行 你有什么好的编程习惯 哈希冲突怎么解决 反问(据说是进公共池然后给部门挑人,怎么和一面说的不一样) 哔哩哔哩(C++多媒体,一面)作者:@牛客619985740号 项目以及相关知识点tcp三次握手,为什么要三次握手多态的实现原理const关键字构造函数为什么不能声明为虚函数析构函数为什么要声明为虚函数c++内存分布模型熟悉哪种STL容器迭代器失效问题share_ptr是线程安全的吗模板可以使用选虚函数吗,为什么二叉树的层序遍历 哔哩哔哩(C++多媒体,二面)作者:@牛客619985740号 项目以及相关知识点左值和右值是什么右值引用是什么,解决了什么std::move()unique_ptr解决了什么,怎么解决的static关键字作用static声明的成员函数和成员变量如何在其他文件访问一个static修饰的变量在一个.h文件中声明一个static的函数,在.c文件中实现,在别的文件中能调用吗拷贝构造为什么传递一个const引用,如果不使用引用传递呢反转链表 哔哩哔哩(C++多媒体,三面)作者:@牛客619985740号 音视频相关知识点tcp三次握手,为什么要三次构造函数为什么不能是虚函数,能这么写吗,这么写会发生什么析构函数为什么是虚函数c++中调用c库中的接口假如父类的构造函数中调用了一个虚函数,调用该构造函数时调用的是父类的还是子类的两道算法
https://mp.weixin.qq.com/s/byLYv6hzDEq9GD17ly6gfw
https://mp.weixin.qq.com/s/B44lyGuz446Ly_m92uQ_aghttps://mp.weixin.qq.com/s/2tyyZvrf1HyRactsDTjD8Q