crt默认不记录分配上下文,故泄漏报告仅显示{123}编号而无文件行号;需先运行获取编号,再在main开头调用_crtsetbreakalloc(123)中断定位到new[]语句。

Windows下用_CrtSetDbgFlag检测new[]泄漏但不报行号
默认启用CRT调试堆后,_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF) 能捕获 new[] 分配的泄漏,但报告只显示 {123} 编号,没有文件和行号——因为 CRT 默认不记录分配上下文。这在排查动态数组(如 int* arr = new int[100];)时特别棘手,容易误判为“没泄漏”或归错位置。
必须配合 _CrtSetBreakAlloc(123) 才能中断到具体分配点。实操要点:
- 先运行一次获取泄漏编号(比如输出
{456}) - 在
main()开头插入_CrtSetBreakAlloc(456); - 调试启动(F5),程序会在
new int[100]那行中断,调用栈清晰可见 - 务必删掉
_CrtSetBreakAlloc再提交代码,否则用户运行直接崩溃
Linux/macOS用AddressSanitizer抓new[]越界与泄漏
AddressSanitizer 对 new[] 的支持比 CRT 更完整:它能同时检测堆缓冲区溢出(如 arr[100] = 0;)、释放后使用(delete[] arr; arr[0] = 1;),以及未匹配的 delete/delete[](比如用 delete 释放 new[] 分配的内存)。
编译命令必须带 -fsanitize=address -g,否则只报地址不报行号。注意两点:
-
ASan不检测全局 POD 数组(如static char buf[1024];),只管堆上分配 - 若项目重载了
operator new[]但漏掉operator new[](size_t, void*)(placement 版本),STL 容器(如std::vector)扩容时会绕过你的监控,导致泄漏漏报
Valgrind Memcheck识别new[]泄漏但需禁用优化
valgrind --leak-check=full ./program 能准确区分 new 和 new[] 泄漏,输出中会明确标出 operator new[](unsigned long) 调用栈。但它对编译优化敏感:
- 必须用
-g -O0编译,否则行号错乱或丢失 - 生产环境可改用
-Og(优化但保留调试信息),避免-O2导致调用栈折叠 - Valgrind 不支持某些系统调用(如
epoll_wait在容器中可能卡住),高并发场景建议优先用 ASan
自定义new[]/delete[]重载时容易漏掉placement版本
很多人重载 operator new[] 和 operator delete[] 做计数,却忘了 operator new[](size_t, void*) 和 operator delete[](void*, void*)。后果是:std::string 构造、std::vector 内部扩容等场景会走 placement 版本,绕过你的日志和计数逻辑,造成“CRT 报泄漏,但你的计数器显示平衡”的假象。
补全写法示例:
void* operator new[](size_t sz, void* ptr) noexcept { return ptr; }
void operator delete[](void*, void*) noexcept {}
否则,哪怕只漏一个重载,new[] 泄漏就可能藏在 STL 实现细节里,根本查不到源码行。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











