在上篇 C++ delete操作报错(一) 中,讲到自定义对象在delete和delete []之间的区别,并且在VS报错的情况。
先讲一下delete和delete[] 的区别:
有个例子:
class CustomTest
{
public:
CustomTest()
{
a = 0;
cout<<"CustomTest 构造"<<a<<endl;
}
~CustomTest()
{
cout<<"Custom 析构~"<<a<<endl;
}
public:
int a;
};
测试程序:
void NewDeleteTest()
{
CustomTest* pBuf = NULL;
int nTestCount = 5;
pBuf = new CustomTest[nTestCount];
//init pBuf
for (int i = 0; i < nTestCount; i++)
{
pBuf[i].a =i;
cout<<"a = "<<pBuf[i].a<<endl;
}
CustomTest *pTest = pBuf+2;
cout<<"pTest a = "<<pTest->a<<endl;
delete []pBuf; //delete pBuf //区别就在这个地方---------------------------------------
pBuf = NULL;
}
若使用的是delete pBuf,结果为:
若使用的是delete []pBuf ,结果为:
可以看到:
用delete,只是释放了一个Custom对象,但是数组中有五个对象,
用delete[], 五个Custom对象都释放了。
注:这个是用的codeBlock IDE, MinGW编译器,用它是因为不报错,好看结果,嘿嘿。
这边了解了一个基本问题,就是对于指向对象数组的指针,用delete,只会删除数组的第一个元素。
用delete[] 会将数组中的对象都释放掉。
好,现在讨论在VS下用delete删除一个对象数组指针时报错的问题。
根据报错,我们会跟到一个dbgdel.cpp文件中,
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
先看一个数据结构定义:就是DEBUG下系统对内存进行管理的一个数据结构:
_CrtMemBlockHeader * pHead;
typedef struct _CrtMemBlockHeader
{
struct _CrtMemBlockHeader * pBlockHeaderNext;
struct _CrtMemBlockHeader * pBlockHeaderPrev;
char * szFileName;
int nLine;
#ifdef _WIN64
/* These items are reversed on Win64 to eliminate gaps in the struct
* and ensure that sizeof(struct)%16 == 0, so 16-byte alignment is
* maintained in the debug heap.
*/
int nBlockUse;
size_t nDataSize;
#else /* _WIN64 */
size_t nDataSize;
int nBlockUse;
#endif /* _WIN64 */
long lRequest;
unsigned char gap[nNoMansLandSize];
/* followed by:
* unsigned char data[nDataSize];
* unsigned char anotherGap[nNoMansLandSize];
*/
} _CrtMemBlockHeader;
可以看出来,这是一个双向的链表,(每一个结构中都包含一个pre和next指针)。 还包含如下信息: 申请空间的文件名、所在行数、用户申请的数据大小, 内存块的类型,用于内存管理信息的额外空间。
现在来看出错的断言:
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
我们传进去的参数, pHead->nBlockUse的值为147 看看是如何判断一个内存块的是否是合法的。
#define _BLOCK_TYPE_IS_VALID(use) (_BLOCK_TYPE(use) == _CLIENT_BLOCK || \
(use) == _NORMAL_BLOCK || \
_BLOCK_TYPE(use) == _CRT_BLOCK || \
(use) == _IGNORE_BLOCK)
而BLOCK_TYPE(use)又是怎么的宏定义呢:
#define _BLOCK_TYPE(block) (block & 0xFFFF)
我们的参数穿进去之后,还是147啊。 而
CLIENT_BLOCK 4
NORMAL_BLOCK 1
CRT_BLOCK 2
IGNORE_BLOCK 3
没一个条件能成立,所以断言不成立,系统就会弹出那么大的错误提示框。