C++程序crash分析和内存检测

一、 调试与排错篇(怎么抓出底层 Bug)

  1. 为什么 msvsmon.exe 会意外退出?

原因:你的程序发生了极其严重的内存破坏(如严重的野指针、数组越界),直接把 VS 的调试器进程内存给写坏了。

还有个原因是内存泄漏越来越大,直接调试器崩了

应对:不要指望普通调试器能拦住,必须使用 AddressSanitizer (ASan 地址清理器)。它会抢在系统崩溃前拦截信号,并精确打印出内存越界发生的源文件、行号以及内存初始分配的位置。

  1. VS 调试设置的正确姿势

勾选异常:C++ 程序重点在 Win32 Exceptions 里勾选 0xC0000005 Access violation(访问冲突)等致命错误。不需要勾选 <不在此列表中的所有 C++ Exceptions>。

ASan 弹窗拦截:遇到 0xE0736171 Sanitizer raw access violation,需要取消勾选该异常,让 ASan 顺利把日志打印到"输出"窗口,而不是被 VS 弹窗打断。

重要原则:修改异常设置、开启 ASan 都不需要重新编译源码(但开启 ASan 后,需要重新生成解决方案,因为要在编译期插桩)。

二、 内存管理与指针篇(怎么写出安全的代码)

  1. std::shared_ptr 与 std::unique_ptr 的所有权

shared_ptr 内部通过引用计数管理内存。传值/拷贝才会增加计数;解引用(*)或调用函数不会改变计数。

unique_ptr 独占所有权。绝对不要用 release() 返回裸指针,这会引发严重的内存泄漏或所有权混乱,直接 return std::move(ptr) 或 return ptr; 即可。

多线程安全:即使是 shared_ptr,如果在一个线程使用它,另一个线程执行了 clear() 或 delete,依然会导致原指针变成野指针。需要配合 mutex 并在使用前进行拷贝。

  1. 回调函数的陷阱

如果第三方回调返回一个裸指针 SNPdata*,你必须明确它是否是用 new 分配的。如果是,立刻用 std::unique_ptr 接住接管所有权;如果它指向静态内存或成员变量,千万不要去接,否则 delete 时会崩溃。

三、 C++ 隐式转换与 Qt 智能指针篇(为什么能编译?)

cpp 复制代码
QPointer<XMessageWidget>gl_getWidget(void)
{
    return QPointer<XMessageWidget>(MainWindow::gl_pMessageWidget);
}

XMessageWidget widget = gl_getWidget();  //编译会出错,要用指针接,QPointer和裸指针都行,因为裸指针接会做隐式的类型转换
  1. operator T*() 是什么?

这是 类型转换运算符。QPointer 内部实现了它,允许编译器在需要裸指针时,自动把 QPointer 转成 T*。

  1. 隐式转换的"1+∞"法则

限制:最多只能发生 1 次"用户自定义转换"(如 operator T* 或单参数构造函数),但可以发生多次标准转换(如派生类转基类、数值转换)。

当你传 QPointer 给要求 QObject* 的函数时:QPointer

→

→ Widget*(1次自定义)

→

→ QObject*(1次继承转型)。刚好1次自定义,合法!

  1. 为什么传参能编译,但初始化变量不行?

传参:void doSomething(QObject* obj); doSomething(pMessageWidget); 编译器会自动隐式转换。

初始化变量:XMessageWidget pWidget = gl_getMessageWidget(); 少写了星号 。这是把指针塞给实体对象,严重类型不匹配。必须写成 QPointer pWidget = ...; 或 XMessageWidget pWidget = ...;

四、 Qt 中 QPointer 的核心真理

作用:QPointer 是一种弱引用(专用于 QObject 及其子类)。当对象被销毁时,QPointer 会自动变成 nullptr,防止野指针。

按值传递:void doSomething(QPointer obj) 中,如果外部对象被销毁,函数内部的 obj 同样会自动置空,if(obj) 绝对能识别出来。

安全防线:如果传参时遇到的是裸指针 QObject*,原对象被销毁后,函数内部拿到的依然是原来的地址(野指针)。所以在使用裸指针前,必须判空。

💡 最经典的踩坑:QPointer 实例化时,必须包含 T 的完整定义头文件。如果只有前置声明,编译器在内部模板推导时直接报错 C2661(没有匹配的构造函数)。

五、模板实例化时需要有完整的类

有些报错答非所问,可能是模板展开报错,可能是没有识别到完整的类,加一下头文件就行解决

相关推荐
椒颜皮皮虾྅1 小时前
让 C# 读懂整张图:DeploySharp 驱动 PaddleOCR v4/v5/v6,打通 OCR 全流程
开发语言·人工智能·深度学习·学习·c#·ocr·cuda
昂好的day1 小时前
C# 同步异步与多线程:Thread / Task / 线程池一次讲透(上篇)
开发语言·windows·c#
Java后端的Ai之路1 小时前
01、Java并发编程:学习攻略如何才能学好并发编程?
java·开发语言·学习
ShineWinsu1 小时前
对于Qt:QLabel常见属性的解析
c++·qt·面试·笔试·gui·标签·qlabel
zwc32104320552 小时前
Day 5:threshold与inRange阈值分割
c++·图像处理·人工智能·opencv·算法·计算机视觉
OxYGC2 小时前
[工程] PHP2Shell 漏洞解析:两条 PHP 内核 RCE,为什么应用层的防护全部失效
android·开发语言·php
小徐不徐说2 小时前
数据库存储基础:理解表结构、主键、事务与 BLOB
开发语言·数据库·c++·qt·程序设计
草莓熊Lotso2 小时前
【C++ 基于微服务的即时通讯系统】网关基建:cpp-httplib 与 WebSocketpp 从入门到实战
linux·开发语言·数据库·c++·redis·微服务·云原生
李纲明2 小时前
WordPress 媒体库上传失败或一直转圈:先核 PHP 上传限制与目录权限,再查安全插件与对象存储
运维·开发语言·安全·php·wordpress·媒体库·devdiy