在用到delete的时候,我们往往会针对类对象与类对象数组做不同删除,在这背后编译器是如何做的?

#include<iostream>
using namespace std; class A{
int a;
public: ~A(){
printf("delete A\n");
}
}; int main(){
A *pa = new A ;
A *pas = new A[] ;
//delete []pas; //详细流程
//delete []pa; //会发生什么
//delete pas; //会怎么样 getchar();
}

从汇编的角度来看:在C++的delete与delete[]对应'scalar deleting destructor'或 'vector deleting destructor'

void scalar_deleting_destructor(A* pa)
{
pa->~A();
A::operator delete(pa);
}
void vector_deleting_destructor(A* pa, size_t count)
{
for (size_t i = ; i < count; ++i)
pa[i].~A();
A::operator delete[](pa);
}
//delete  []pas;                //会调用10次析构函数在free
//delete []pa;                //超出范围的内存会被收回,VS: 编译正确,运行出错

//delete pas;                    //会怎么样,VS: 编译通过,运行报错   VC:编译通过,可以运行,但只调用一次析构函数

一下用于VS的解释:
参考

好,现在讨论在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

没一个条件能成立,所以断言不成立,系统就会弹出那么大的错误提示框。

 
但是为什么我们穿进去的参数会是147呢?
参考:http://m.oschina.net/blog/55763
 
05-19 12:35