'scalar deleting destructor' 和 'vector deleting destructor'的区别
Posted on 2013-12-25 13:43 huhuuu 阅读(6600) 评论(0) 编辑 收藏 举报在用到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[10] ; //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 = 0; 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