Momenta C++ ⼀⾯凉经
进程内存飙升时你会用什么命令排查?
先找高内存进程,再看内存构成,最后判断是否泄漏或缓存失控。
常用命令:
- ps aux --sort=-%mem | head
- top -p <pid> / htop
- pmap -x <pid>
- cat /proc/<pid>/status(看 VmRSS、VmSize)
- 测试环境可用:valgrind --leak-check=full ./app
你怎么查看 CPU 状态?
从系统、核、进程三层判断是否 CPU 瓶颈或 IO wait 偏高。
常用命令:
- uptime / top
- mpstat -P ALL 1
- pidstat -u 1
- vmstat 1
云服务器内存不足你会怎么处理?
思路:先止血,再定位,再治理。
- 止血:扩容、临时开 swap、限流降级
- 定位:内存泄漏、缓存策略不当、流量突增
- 治理:优化数据结构与回收策略,完善监控告警
你项目里用过哪些 C++ 版本特性?
按“场景 + 收益”回答更好:
- auto、范围 for、nullptr、enum class
- unique_ptr/shared_ptr 做资源管理
- thread/mutex/condition_variable 做并发控制
- 移动语义 + emplace_back 做性能优化
- chrono 做耗时统计
你平时怎么用 gdb?
典型流程:
- gdb ./app 或 gdb ./app core
- b <file:line|func>
- run
- n/s 单步
- p、info locals 看变量
- bt 看调用栈
- thread apply all bt 看全部线程栈
gdb 怎么查看调用栈?
- bt:当前线程调用栈
- thread apply all bt:所有线程调用栈
- frame <n>:切换栈帧查看上下文
你平时怎么编译项目?
单文件可直接 g++,项目建议 Makefile/CMake。
g++ -std=c++17 -O2 -g main.cpp -I./include -L./lib -lfoo -o app
说一下 Makefile 怎么写
核心是变量清晰、规则完整、支持增量编译。
CXX := g++ CXXFLAGS := -std=c++17 -O2 -g -Wall -Wextra INCLUDES := -I./include LDFLAGS := -L./lib LDLIBS := -lfoo -lpthread SRCS := main.cpp foo.cpp OBJS := $(SRCS:.cpp=.o) TARGET := app all: $(TARGET) $(TARGET): $(OBJS) $(CXX) $(OBJS) -o $@ $(LDFLAGS) $(LDLIBS) %.o: %.cpp $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@ clean: rm -f $(OBJS) $(TARGET) .PHONY: all clean
-g -I -L` 分别干什么?
- -g:生成调试符号
- -I:头文件搜索路径
- -L:库文件搜索路径
给一段代码让你找问题,你怎么分析?
固定套路:
- 编译期:类型/声明问题
- 运行期:越界、空指针、悬空引用
- 逻辑层:边界条件遗漏
基本上指出哪一行错、为什么、怎么改。
题目代码
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <thread>
#include <mutex>
using namespace std;
class UserCache {
public:
const string& getName(int uid) {
lock_guard<mutex> lk(mu_);
if (nameById_.count(uid) == 0) {
string tmp = "user_" + to_string(uid);
nameById_[uid] = tmp;
}
return nameById_[uid];
}
void eraseIfOdd(int uid) {
if (uid % 2 == 1) {
lock_guard<mutex> lk(mu_);
nameById_.erase(uid);
}
}
private:
unordered_map<int, string> nameById_;
mutex mu_;
};
int parseScore(const string& s) {
int sign = 1;
size_t i = 0;
if (s[0] == '-') {
sign = -1;
i = 1;
}
int v = 0;
for (; i <= s.size(); ++i) {
if (s[i] < '0' || s[i] > '9') break;
v = v * 10 + (s[i] - '0');
}
return sign * v;
}
int sumTopK(vector<int>& a, size_t k) {
int sum = 0;
for (size_t i = 0; i <= k; ++i) {
sum += a[i];
}
return sum;
}
int main() {
UserCache cache;
vector<string> ids = {"12", "-7", "", "9x"};
vector<int> scores;
for (auto& s : ids) {
int x = parseScore(s);
scores.push_back(x);
}
thread t1([&](){
for (int i = 0; i < 10000; ++i) {
const string& n = cache.getName(i % 10);
if (n.size() > 20) cout << n << endl;
}
});
thread t2([&](){
for (int i = 0; i < 10000; ++i) {
cache.eraseIfOdd(i % 10);
}
});
t1.join();
t2.join();
cout << "sum=" << sumTopK(scores, 3) << endl;
return 0;
}
参考分析
- parseScore 越界 s[0] 在空串时越界 i <= s.size() 会在 i == s.size() 时访问 s[i] 越界 修复:先判空;循环改为 i < s.size()
- sumTopK 越界 i <= k 会访问 k+1 个元素 k 可能超过 a.size() 修复:i < min(k, a.size())
- 并发悬空引用风险 getName 返回 unordered_map 内部元素引用 锁释放后别的线程 erase/rehash 可能使引用失效 修复:getName 返回 string 值(副本)而不是引用
正确答案
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <thread>
#include <mutex>
using namespace std;
class UserCache {
public:
string getName(int uid) {
lock_guard<mutex> lk(mu_);
auto it = nameById_.find(uid);
if (it == nameById_.end()) {
it = nameById_.emplace(uid, "user_" + to_string(uid)).first;
}
return it->second;
}
void eraseIfOdd(int uid) {
if (uid % 2 == 1) {
lock_guard<mutex> lk(mu_);
nameById_.erase(uid);
}
}
private:
unordered_map<int, string> nameById_;
mutex mu_;
};
int parseScore(const string& s) {
if (s.empty()) return 0;
int sign = 1;
size_t i = 0;
if (s[i] == '-') {
sign = -1;
++i;
}
int v = 0;
for (; i < s.size(); ++i) {
if (s[i] < '0' || s[i] > '9') break;
v = v * 10 + (s[i] - '0');
}
return sign * v;
}
int sumTopK(const vector<int>& a, size_t k) {
int sum = 0;
size_t n = min(k, a.size());
for (size_t i = 0; i < n; ++i) {
sum += a[i];
}
return sum;
}
int main() {
UserCache cache;
vector<string> ids = {"12", "-7", "", "9x"};
vector<int> scores;
for (const auto& s : ids) {
scores.push_back(parseScore(s));
}
thread t1([&]() {
for (int i = 0; i < 10000; ++i) {
string n = cache.getName(i % 10);
if (n.size() > 20) cout << n << '\n';
}
});
thread t2([&]() {
for (int i = 0; i < 10000; ++i) {
cache.eraseIfOdd(i % 10);
}
});
t1.join();
t2.join();
cout << "sum=" << sumTopK(scores, 3) << endl;
return 0;
}
合并区间题,给出思路和代码
思路:先按起点排序,再线性扫描合并重叠区间。
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
if (intervals.empty()) return {};
sort(intervals.begin(), intervals.end(),
[](const vector<int>& a, const vector<int>& b) {
return a[0] < b[0];
});
vector<vector<int>> res;
res.push_back(intervals[0]);
for (size_t i = 1; i < intervals.size(); ++i) {
auto& last = res.back();
if (intervals[i][0] <= last[1]) {
last[1] = max(last[1], intervals[i][1]);
} else {
res.push_back(intervals[i]);
}
}
return res;
}
};
C++面试总结 文章被收录于专栏
本专栏系统梳理C++面试高频考点,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力。
查看10道真题和解析