校招 未知部门 / 后端-C++ / 一面

[面试日期] 2026-07-17 [面试时长] 未知
[学校背景] 浙江大学 | 985 [学历背景] 未知
[发布人] 面试之星官方收录
<h2>字节跳动C++ 一面 面经</h2> <h1>1. 虚函数底层是怎么实现的?纯虚函数和普通虚函数有什么区别?</h1> <ol> <li>带虚函数的类通常会多一个虚函数表指针,指向该类的虚表。</li> <li>调用虚函数时,先找对象里的虚表指针,再按偏移取函数地址,实现运行时多态。</li> <li>构造过程中虚表指针会按基类到派生类逐步切换,所以构造里调虚函数通常走当前正在构造的那一层。</li> <li>纯虚函数在虚表对应项一般是占位/抽象接口,含纯虚函数的类不能直接实例化。</li> <li>普通虚函数可以有默认实现,派生类可覆盖;纯虚函数强制派生类提供实现,除非派生类也继续保持抽象。</li> </ol> <h1>2. 左值、右值、将亡值怎么区分?什么时候会触发移动而不是拷贝?</h1> <ol> <li>左值一般可取地址、有名字;纯右值是临时量;将亡值多来自 <code>std::move</code> 或返回可移动对象。</li> <li>移动构造/移动赋值吃的是右值引用,目的是“偷”资源,避免深拷贝。</li> <li>有名字的右值引用变量本身是左值,要继续往下传通常还得再 <code>std::move</code>。</li> <li>返回局部对象时编译器常做 RVO/NRVO,不一定真走移动。</li> <li>被 <code>const</code> 限定的对象即使 <code>std::move</code>,也往往只能走拷贝,因为移动接口通常要非 const 右值引用。</li> </ol> <h1>3. <code>std::vector</code> 扩容时为什么可能导致迭代器失效?怎么安全地边遍历边删?</h1> <ol> <li>容量不足时会分配更大内存、搬迁元素、释放旧缓冲,原指针/迭代器/引用都会失效。</li> <li><code>push_back</code>、<code>insert</code>、<code>reserve</code> 不够时都可能触发扩容。</li> <li><code>erase</code> 会使被删位置及其后的迭代器失效,但通常可接住返回的下一位置迭代器继续。</li> <li>边遍历边删优先用“迭代器 = erase(it)”写法,或先记下要删的,再统一删。</li> <li>若能预估大小,先 <code>reserve</code>,能减少扩容次数和失效风险。</li> </ol> <h1>4. <code>std::map</code> 和 <code>std::unordered_map</code> 在实现、复杂度、使用场景上怎么选?</h1> <ol> <li><code>map</code> 一般是红黑树,有序,查找/插入/删除平均 O(log n)。</li> <li><code>unordered_map</code> 是哈希表,平均 O(1),最坏退化到 O(n),且无序。</li> <li>需要范围查询、有序遍历、稳定最坏复杂度时偏向 <code>map</code>。</li> <li>只要按 key 精确查找、吞吐优先,且能提供好的哈希,偏向 <code>unordered_map</code>。</li> <li><code>unordered_map</code> 对自定义 key 要正确实现哈希和相等语义,否则容易碰撞或查不到。</li> </ol> <h1>5. 结构体内存对齐规则是什么?<code>#pragma pack</code> 乱改可能带来什么问题?</h1> <ol> <li>成员按自身对齐要求落在对齐边界上,结构体总大小通常对齐到最大成员对齐值。</li> <li>中间可能出现 padding,所以 <code>sizeof</code> 往往大于成员大小之和。</li> <li>合理排布成员(如从大到小)能减少空洞,降低内存占用。</li> <li>强制 1 字节打包可省内存,但可能让访问变慢,某些架构上未对齐访问还会更贵甚至异常。</li> <li>跨平台、网络协议、mmap 共享结构时,对齐和打包策略必须两端一致,否则字段错位。</li> </ol> <h1>6. 互斥锁和自旋锁怎么选?什么场景自旋更合适?</h1> <ol> <li>互斥锁拿不到锁时线程会睡眠,适合临界区较长、竞争不极端的场景。</li> <li>自旋锁会忙等,不切换上下文,适合临界区极短、且预期很快能拿到锁的场景。</li> <li>单核或长时间持锁时自旋通常很亏,会空转烧 CPU。</li> <li>多核、锁持有时间极短(如改几个原子状态)时自旋更有优势。</li> <li>实际中也可组合:先自旋一小会儿,再降级到睡眠锁,减少无效调度。</li> </ol> <h1>7. <code>std::atomic</code> 的 <code>memory_order</code> 大致怎么理解?日常该怎么用?</h1> <ol> <li><code>relaxed</code> 只保证原子性,不保证跨线程的额外顺序约束。</li> <li><code>acquire/release</code> 常成对使用:release 之前的写,对之后成功 acquire 的一侧可见。</li> <li><code>acq_rel</code> 同时带获取和释放语义,多见 read-modify-write。</li> <li><code>se</code> 最强,提供全局总序,最好懂但可能更贵。</li> </ol>
AI 推荐面试题