上面代码的结果会走到show()里显示出show(这跟编译环境有关,vc2003下测试结果是这样)。如果你了解c++的vtable机制就明白这是怎么回事。
如果不明白也没关系,我下面说个大概。
首先CA对象被创建又被删除。如果此时调用p->f()多半会crash。
第二块代码可视为一些正常的操作,new了一个q,然后对它进行了一些赋值。
如果你不明白vtable机制,那你只要知道,最后一行的 “p->f();”会执行变量q所指向的变量所指向的变量所标示的地址。(这里没打错字,是两个“所指向的变量”)
这里我“心地善良”的给这个值赋上了一个合法的函数地址show。但实际程序中q所指向的变量有可能是任意值,它再指向的变量就更是任意值了。
那程序就不知道跑哪里去了。如果这个值过于离谱,那算你运气好,程序会立即crash,而你就知道错误位置在哪了。但讨人厌的是,它有可能是一个合法地址,那程序就继续走下去,
但迟早会crash,并且调用堆栈面目全非(原因牵涉到“调用堆栈的推导”的问题这里就不多说了),
到时就根本无从知道原来是调用了被删除的p对象而导致的。
5.2 使用Debugging tools for windows查看.dmp文件(错误报告)
a. 准备好程序对应的代码,exe文件,pdb文件(编译时在编译输出目录里)
b. 安装WinDbg
c. 在winDbg里把Symbol目录设在.pdb所在目录,Image目录设在.exe所在目录,code目录设到代码目录。
d. 打开.dmp文件
e. 输入命令.ecxr。(此命令使环境回到崩溃时的状态)
f. 打开调用堆栈(ALT + F6)查看Crash的位置
g. 进行分析
简介
(FinalCheck能检测出的错误列表见附录1)
BoundsChecker是一个很强大的调试工具。这里只简单介绍如何用它的FinalCheck模式定位比较难定位的错误。
FinalCheck模式简单来说就是BoundsChecker在你的代码里加一些诊断代码来检查平时比较难查出的内存越界,错误的指针使用等。
不过付出的代价就是程序跑起来会比较慢,所以在不用时最好是把FinalCheck模式关掉。特别是发布前。
BoundsChecker下载地址
ed2k://|file|BoundsChecker.v7.2.rar|62579029|6032ED8CA789C23D1CC1553946F814A0|h=D3OR5R3FZXJSV7I5A7HWTFHSRZPTLN4N|/
启用FinalCheck模式(基于Visual Studio 2003)
1. 在VC的菜单里的“工具->BoundsChecker”
a. 选中“Error Detection” (选中此项让你在调试运行时让BoundsChecker同时检测程序的错误,不选中就是普通的调试程序)
b. 选中“Log Event”
c. 去掉“Display error and pause”(出现错误时是否立即提示,可以试试选中它看看是什么效果)
d. 选中FinalCheck(编译时加入BoundsChecker的诊断代码,不再需要此功能时,要把这个选项去掉再把工程重新编译一遍)
2. 在VC的菜单里打开“工具->BoundsChecker->Options”确认里面的“Memory Tracking->Enable FinalCheck”被选中。
3. 重新编译你的工程,这时BoundsChecker会在编译的过程中插入些诊断代码用于之后的监测。(如果编译不通过,参看附录2)
4. 按F5调试运行你的程序
-这时你的程序就在BoundsChecker的监测下运行起来了。
查看错误信息
此时你的解决方案里会多出一个 DevPartner Sessions->BoundsChecker->BoundsChecker-Active Session
双击它可以看到目前出现的错误。
我们关注Errors那个页签,其他的可以自行研究。这里有很多错误。有的会有源码。
不明的这个错误说什么的可以右键点击这个错误,点击explain里面有很详细的解释。
性能及相关设置
FinalCheck是很耗cpu和内存资源的,所以如果机器不好,可能会非常慢。这里可以做想应设置先去掉一些检测功能来加快速度。
打开BoundsChecker的选项“工具->BoundsChecker->Options”
1. Resource Tracking里的Enable resource tracking可以先去掉,因为暂时不需要对资源的检测
2. Memory Tracking中是对不同的情况进行监测,可以先去掉一些你不关心的。或是一次只监测一部分。
其他问题:
1. 如果你的解决方案里含有多个项目,那要注意FinalCheck是对于项目的,要注意哪个是当前项目。
2. 遇到其他问题可以查看BoundsChecker的帮助,或在网上搜索。帮助在安装目录下的help里的bc7.chm
3. 如果不使用集成到VC里的BoundsChecker,也可以使用安装目录下的BC7.exe去打开你的程序exe运行。
但编译还是要按上面所说的编译。另注意BC7.exe的"setting->Memory Tracking->Enable FinalCheck"要被选上。
4. 如果过程中你遇到问题欢迎跟贴。
附录1: BoundsChecker的FinalCheck模式能检测出的错误列表
Pointer Errors - 指针错误
Array index out of range - 使用越界的数组索引
Assigning pointer out of range - 使用越界的指针
Expression uses dangling pointer - 使用野指针
Expression uses unrelated pointer - 不相关指针相互比较
Function pointer is not a function - 函数指针指向的不是函数地址
Memory Errors - 内存错误
Reading overflows memory - 越界读内存
Reading uninitialized memory - 读未初始化的内存
Writing overflows memory - 越界写内存
Leak Errors - 泄漏
Memory leaked due to free - 未释放内嵌指针导致的内存泄漏
Memory leaked due to reassignment - 指针重赋值导致的内存泄漏
Memory leaked leaving scope - 离开作用域导致的内存泄漏
Returning pointer to local variable - 返回局部变量的指针
附录2:与FinalCheck冲突的编译参数
在使用FinalCheck重新编译工程的过程中可能会出现一些编译错误,因为FinalCheck跟一些编译选项有冲突,
目前所知的有:
a. 关掉“常规->全程序优化”
b. “C/C++ -> 优化 -> 内联函数展开”设成默认。
遇到其他问题对照它给出的信息做相应设置修改就行了