'scalar deleting destructor' 和 'vector deleting destructor'的区别
在用到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
没一个条件能成立,所以断言不成立,系统就会弹出那么大的错误提示框。
参考:http://m.oschina.net/blog/55763
'scalar deleting destructor' 和 'vector deleting destructor'的区别的更多相关文章
- C++ vector和list的区别
1.vector数据结构vector和数组类似,拥有一段连续的内存空间,并且起始地址不变.因此能高效的进行随机存取,时间复杂度为o(1);但因为内存空间是连续的,所以在进行插入和删除操作时,会造成内存 ...
- 【转】java 容器类使用 Collection,Map,HashMap,hashTable,TreeMap,List,Vector,ArrayList的区别
原文网址:http://www.360doc.com/content/15/0427/22/1709014_466468021.shtml java 容器类使用 Collection,Map,Hash ...
- 源码分析三(Vector与ArrayList的区别)
前面讨论过ArrayList与LinkedList的区别,ArrayList的底层数据结构是数组Object[],而LinkedList底层维护 的是一个链表Entry,所以对于查询,肯定是Array ...
- 一道java笔试题目:Vector和ArrayList的区别
Vector和ArrayList的区别 线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构这些类均在java.util包中本文试图通过 ...
- C/C++中vector与list的区别
1.vector数据结构vector和数组类似,拥有一段连续的内存空间,并且起始地址不变.因此能高效的进行随机存取,时间复杂度为o(1);但因为内存空间是连续的,所以在进行插入和删除操作时,会造成内存 ...
- Vector和ArrayList的区别联系,Hashtable和HashMap的区别联系
Vector.Hashtable是早期的集合类,线程安全,但是效率低下,被相同原理.结构的ArrayList.HashMap取代. 1.Vector和ArrayList的区别和联系: 联系:实现原理相 ...
- ArrayList、Vector、LinkedList的区别
ArrayList.Vector.LinkedList的区别 1.底层数据结构: ArrayList底层实现是动态数组 Vector底层实现是动态数组 LinkedList底层实现是双链表 2.扩容 ...
- 转-vector与list的区别
转自:C++ vector和list的区别 数据结构的区别 vector vector与数组类似,拥有一段连续的内存空间,并且起始地址不变.便于随机访问,时间复杂度为O(1),但因为内存空间是连续的, ...
- ArrayList、Vector、LinkedList的区别联系?
1.ArrayList.Vector.LinkedList类都是java.util包中,均为可伸缩数组. 2.ArrayList和Vector底层都是数组实现的,所以,索引数据快,删除.插入数据慢. ...
随机推荐
- Python3.x:open()文件操作
Python3.x:open()文件操作 open/文件操作: #open(路径+文件名,读写模式) #读写模式:r只读,r+读写,w新建(会覆盖原有文件),a追加,b二进制文件.常用模式 f=ope ...
- javascript-高级用法
22.1 安全的类型检测 为什么:typeof 不靠谱, 无法将数组从对象中区分出来, instanceof 有特殊情况,在iframe存在的情况下无法判断另一个iframe内的数组 如何做:Obje ...
- Mininet实验 设置带宽之简单性能测试
原文:设置带宽之简单性能测试 这个实验主要还是说明通过python程序来设定Mininet中的链路带宽. 目的: Python脚本实现自定义拓扑 设置链路的带宽.延迟及丢包率 iperf测试主机间的带 ...
- HDU 3820 Golden Eggs
http://acm.hdu.edu.cn/showproblem.php?pid=3820 题意:n*m的格子,每个格子放金蛋或银蛋,每个格子的金蛋和银蛋都有一个对应的点权,如果有两个金蛋相连,则需 ...
- python 字典获取最大和最小的value
my_dict = {, , } key_max = max(my_dict.keys(), key=(lambda k: my_dict[k])) key_min = min(my_dict.key ...
- Redis为什么要把所有数据放到内存中?
Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘.所以Redis具有快速和数据持久化的特性. 如果不将数据放到内存中,磁盘的I/O速度会严重影响redis的性能.在内 ...
- 雷林鹏分享:Ruby CGI方法
Ruby CGI方法 以下为CGI类的方法列表: 序号方法描述 1CGI::new([ level="query"]) 创建 CGI 对象.query可以是以下值: query: ...
- go_install_x_from_github.sh 从 github 安装 go x tools
bash go_install_x_from_github.sh #!/bin/bash set +e # set -x echo 'GO Utilities: Install golang.org/ ...
- Page.TryUpdateModel 方法
使用来自值提供程序的值更新指定的模型实例. 使用来自值提供程序的值更新指定的模型实例. 命名空间: System.Web.UI程序集: System.Web(System.Web.dll 中) ...
- linux hosts.equiv设置解析
hosts.equiv文件的用途与格式 一. hosts.equiv 文件的用途 /etc/hosts.equiv 和 $HOME/.rhosts 定义了哪些计算机和用户可以不用提供口令就在本地计算机 ...