腾讯 PC客⼾端-C++ ⼀⾯
1. 自我介绍
2. C++ 中的智能指针都有哪些,分别解决什么问题
答案:常见的智能指针主要是 unique_ptr、shared_ptr、weak_ptr,另外还有早期遗留的 auto_ptr,但它已经被废弃。unique_ptr 表示独占所有权,同一时刻只有一个指针拥有对象,不能拷贝只能移动,开销小,最适合所有权明确的场景。shared_ptr 表示共享所有权,多个对象都可以持有同一资源,底层通常有引用计数和控制块,适合多个模块共同管理一个对象的场景。weak_ptr 不拥有对象,只是观察者,通常用来打破 shared_ptr 循环引用,或者在不延长对象生命周期的前提下探测对象是否还活着。工程里不是“智能指针越多越好”,而是先明确所有权。如果生命周期天然受作用域控制,栈对象往往更简单;如果资源归属唯一,优先 unique_ptr;只有真正需要共享时才考虑 shared_ptr。
代码:
#include <iostream>
#include <memory>
using namespace std;
struct Node {
int val;
Node(int x) : val(x) { cout << "ctor\n"; }
~Node() { cout << "dtor\n"; }
};
int main() {
unique_ptr<Node> p1 = make_unique<Node>(1);
shared_ptr<Node> p2 = make_shared<Node>(2);
weak_ptr<Node> p3 = p2;
return 0;
}
3. shared_ptr 为什么会有额外开销,循环引用怎么解决
答案:shared_ptr 的额外开销主要来自两个地方,一个是控制块,里面通常存引用计数、弱引用计数、删除器等信息;另一个是引用计数的修改在多线程场景下往往涉及原子操作。所以它的价值不在于快,而在于共享所有权时能减少手动生命周期管理错误。循环引用最典型的场景是双向关系,比如 A 持有 B,B 又持有 A,如果双方都用 shared_ptr,引用计数永远不会归零,内存就泄漏了。常见做法是一边保留 shared_ptr,另一边改成 weak_ptr,这样既能访问,又不会把生命周期锁死。
代码:
#include <memory>
using namespace std;
struct B;
struct A {
shared_ptr<B> b;
};
struct B {
weak_ptr<A> a; // 这里不能再用 shared_ptr
};
int main() {
auto pa = make_shared<A>();
auto pb = make_shared<B>();
pa->b = pb;
pb->a = pa;
return 0;
}
4. 为什么要做内存对齐
答案:内存对齐主要是为了让 CPU 更高效地访问数据。很多硬件架构更适合按自然边界访问,比如 4 字节整数按 4 字节对齐、8 字节类型按 8 字节对齐。如果对象地址不对齐,轻则访问变慢,重则某些平台直接触发硬件异常。编译器做对齐还有一个重要原因是简化访存逻辑和提高总线利用率。对齐后,CPU 往往能在更少的访存次数里取到完整数据。从 C++ 对象布局看,对齐还会引入 padding,所以成员顺序会影响结构体大小。工程里如果对象数量很大,成员顺序优化有时能明显减少内存占用。
代码:
#include <iostream>
using namespace std;
struct A {
char c;
int i;
short s;
};
struct B {
int i;
short s;
char c;
};
int main() {
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
return 0;
}
5. malloc、calloc、realloc 有什么区别
答案:malloc 负责申请指定字节数的原始内存,申请成功后内容未初始化。calloc 申请的是若干个同样大小的对象,总大小等于两者乘积,而且会把整块内存置零。realloc 用来调整一块已经分配内存的大小,可能原地扩容,也可能重新申请一块更大的内存并把原数据拷过去。它们都只是 C 语言层面的内存管理接口,不会调用构造函数和析构函数,所以管理 C++ 对象时通常不如 new/delete 或 RAII 安全。
代码:
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
int main() {
int* a = (int*)malloc(5 * sizeof(int));
int* b = (int*)calloc(5, sizeof(int));
a = (int*)realloc(a, 10 * sizeof(int));
free(a);
free(b);
return 0;
}
6. new/de
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
本专栏系统梳理C++方向, 大中厂高频高频面试考点 , 内容皆来自真实面试经历,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力.

