最近,在调试代码中发现一个奇怪的现象。程序在运行中,总是会弹出如下的Assert对话框。
经过若干研究,发现原来是由于内存分配不够,会在delete内存时导致该Assert发生.
下面以一个简化的例子来说明这个问题
int main() { char* pChar = new char[2]; pChar[0] = 'a'; pChar[1] = 'b'; pChar[2] = 'b'; delete[] pChar; return 0; }
在这段简单的代码当中,对于pChar的使用明显越界。在debug时,程序总是在执行delete[] pChar时弹出Assert框。
如果程序在运行当中没有问题,那么我自己申请的内存为什么在我自己释放时会发生assert呢?
暂时先将这个问题放在一边,让我们考虑一下另外一个问题:delete[] 是如何知道应该释放多少单元的内存呢?
More Effective C++中已经给出了我们这个问题的答案。http://www.doforfun.net/article/20090401/385.htm。
由此可见,编译器会将申请单元个数的信息记录下来。那么具体到Visual Studio中,微软会为我们的申请的内存添加什么信息呢?
在MSDN中的文章Memory Management and the Debug Heap中http://msdn.microsoft.com/en-us/library/bebs9zyz(v=VS.71).aspx,
已经明确告诉我们Visual Studio 会在我们申请内存前面和后面加入4个字节的所谓No Man's Land。且在No Man's Land中的内容应为
fd fd fd fd。一旦改变,就会引发Assert。
在上面的例子中,由于越界而引起No man's land发生变化。由"fd fd fd fd"变为"62 fd fd fd",所以引起Assert。
在下面的例子当中,我们申请了2个字节的内存,pChar[0],pChar[1]。所以pChar[2]...pChar[5]对应的内存单元应为No man's land。因而当我们使用pChar[6]时,反而在delete[]时不会引发Assert!
有兴趣的同学可以自己尝试改变一下pChar[-1]所对应内存单元的值。在delete[]时也会引发Assert!