用gdb加载core文件或直接调试可定位段错误位置;编译需加-g,常见原因包括空指针解引用、数组越界、使用已释放内存、栈溢出及多线程竞态;AddressSanitizer能主动检测越界和野指针。

怎么看 segmentation fault 发生在哪儿
Linux 下运行程序直接报 Segmentation fault (core dumped),但没行号、没调用栈,等于盲人摸象。先别急着改代码,用 gdb 把 core 文件载入:确保系统允许生成 core(ulimit -c unlimited),运行出错后执行 gdb ./a.out core,进 gdb 后输 bt(backtrace)——90% 的情况能立刻看到崩溃在哪个函数、哪一行。
如果没 core 文件,或者想实时观察,直接 gdb ./a.out 启动,再用 run 运行;崩溃后同样 bt。注意:编译时务必加 -g,否则堆栈里全是 ??:?。
常见触发点和对应检查项
段错误本质是访问了非法内存地址,不是语法错,所以编译器不报错。高频场景有这几类:
-
nullptr解引用:比如p->data前没检查p是否为nullptr - 数组越界:
arr[10]定义了 10 个元素(索引 0~9),却访问arr[10]或arr[-1] - 使用已释放内存:调用
delete p后继续用*p或p->func() - 栈溢出:局部数组过大(如
char buf[1024*1024]),或递归过深 - 多线程竞态:一个线程
delete了对象,另一个线程还在访问其成员
用 AddressSanitizer 快速定位野指针和越界
比 gdb 更主动的手段是编译时加 -fsanitize=address -g,例如:g++ -fsanitize=address -g main.cpp。运行时报错会直接指出哪行越界、哪个指针已释放、甚至堆块分配/释放的完整上下文,信息密度远超 gdb bt。
立即学习“C++免费学习笔记(深入)”;
注意两点:
- ASan 仅支持 Linux/macOS,Windows 上得用 Visual Studio 的诊断工具或 Dr. Memory
- 开启 ASan 后程序变慢、内存占用翻倍,只用于调试,不要带到生产环境
std::vector 和智能指针能防住哪些段错误
它们不能杜绝段错误,但能大幅减少人为失误:
-
std::vector::at()会做边界检查并抛std::out_of_range异常;而operator[]不检查,行为同原生数组 -
std::unique_ptr和std::shared_ptr管理生命周期,避免“释放后使用”,但无法防止reset()后仍用原始指针副本 - 别写
std::shared_ptr,要用(new T) std::make_shared,否则可能因异常导致内存泄漏+后续访问失效内存()
真正容易被忽略的是:容器迭代器失效后继续解引用(如 vec.erase(it) 后还用 *it),这不会被 ASan 捕获,gdb 里看到的崩溃点往往是下游函数,要逆向查容器操作历史。









