会,但需同时指定 --tool=memcheck --leak-check=full --show-leak-kinds=all,否则默认不显示“mismatched free() / delete / delete[]”明确提示,仅以底层错误(如 invalid read)或泄漏分类(definitely lost)间接体现。

valgrind --leak-check=full 会报 mismatched free() / delete / delete[] 吗
会,但默认不显示。Memcheck 默认只标记“释放不匹配”为错误,但不会在终端直接打出 mismatched free() / delete / delete[] 这串文字——它用更底层的提示代替:比如 Invalid read/write、Address 0x... is 0 bytes after a block of size ... alloc'd,或者干脆在泄漏摘要里归类为 definitely lost 却不说明原因。
真正触发明确提示的关键是加参数:--tool=memcheck(虽默认,但显式写上更稳)+ --leak-check=full + --show-leak-kinds=all。只有这三者齐备,Valgrind 才会在报告末尾的 “HEAP SUMMARY” 前,单独列出 “MISMATCHED FREE / DELETE / DELETE[]” 小节,并附上分配和释放两处的完整调用栈。
常见漏掉的点:
- 忘了加
--show-leak-kinds=all,导致只看到still reachable却忽略真正致命的 mismatch - 用
valgrind ./a.out省略了--leak-check=full,此时连泄漏都不报全,更别说匹配问题 - 程序用了
new[]但释放时写了delete ptr(没方括号),Valgrind 能捕获;反过来new配delete[]同样报 mismatch,但后者在多数编译器下可能静默崩溃
怎么复现 new[]/delete 混用并让 valgrind 抓到
写一段最小可复现代码,重点是让对象带析构行为(否则 int 数组可能不报 mismatch,只报 leak):
class Test {
public:
Test() { data = new char[16]; }
~Test() { delete[] data; } // 注意:这里必须用 delete[]
char* data;
};
int main() {
Test* t = new Test[2]; // 分配数组
delete t; // 错!应该用 delete[]
return 0;
}
编译后运行:valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./a.out
你会看到类似输出:
==12345== Mismatched free() / delete / delete [] ==12345== at 0x4C30D3B: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==12345== by 0x10874A: main (test.cpp:12) ==12345== Address 0x4f4a040 is 0 bytes inside a block of size 32 alloc'd ==12345== at 0x4C30F3F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==12345== by 0x10873E: main (test.cpp:10)
注意两点:
- 第一行就明确写了
Mismatched free() / delete / delete [] - 两行
alloc'd和by对比,能清晰看出 new[] 和 delete 的调用位置
为什么有时候 valgrind 不报 mismatch,只报 definitely lost
不是 Valgrind 没检测到,而是你触发的场景让它“降级”处理了。典型情况有:
- 分配的是 POD 类型(如
int*、char*),且没重载operator new[]或operator delete,部分旧版 Valgrind 可能只标记为 leak,不强调 mismatch - 程序在
delete前已崩溃(如 segfault),Valgrind 来不及记录释放动作,只看到内存被分配后从未被正确释放 - 用了
-O2或更高优化等级,编译器把delete内联或优化掉,Valgrind 插桩失效 - 动态链接了某些第三方库(如 Qt 容器),其内部内存管理绕过了标准 new/delete,Valgrind 无法追踪
对策:强制关闭优化(-O0)、确保链接的是未裁剪的调试版 libc++/libstdc++、用 --track-origins=yes 辅助定位未初始化传播路径(虽然不直接解决 mismatch,但常伴生出现)。
查到 mismatch 后,该怎么改才安全
根本原则:分配方式决定释放方式,跟变量名、用途无关。别被 int* arr 这种命名误导。
-
new T→ 必须用delete ptr -
new T[N]→ 必须用delete[] ptr -
malloc/calloc→ 必须用free - 现代 C++ 中,优先换掉裸指针:
std::vector<t></t>替代new T[N],std::unique_ptr<t></t>替代new T,std::unique_ptr<t></t>替代new T[N]
特别注意:如果类里有指针成员并在析构中释放,new[] 创建对象数组时,只有第一个对象的析构函数会被调用(因为 delete 不知道数组长度)。所以 new[] + 自定义析构类 + delete 是双重危险——既 mismatch,又漏析构。这种情况 Valgrind 通常会同时报 mismatch 和 invalid read(因后续对象未析构,其成员指针仍 dangling)。











