使用delete释放new[]的空间造成的错误分析

曲折探索后,这个问题算是水落石出。

我们都被告诫,new和delete,new[]和delete[]要成对出现。如果使用delete 释放new[] 申请的空间会发什么?如下:

T* p = new T [1024];

....//do something

delete p;//会发生什么?

我先告诉你,如果T是一个base type(如,int、double、char),你会发现,程序依然正确运行,不仅如此,内存空间也被正确释放。它的正确运行,让很多人对delete[]和delete的区别的探索就此终止。也难怪在国内的博客中分析delete和delete[]的原理和delete 释放new[]的文章少之又少,很多相关的文章关于这个问题一句带过。

如果代码是这样的:

class A
{
    public:
    int m;
    ~A()
    {}
};

int main()
{
    A* ptr = new A[1024];
    delete ptr;
    return 0;
 }

你可以测试一下这段代码,在VS和g++下都测试一下,看看都出现什么结果。这会增加你日后在程序调试bug的经验(我已经遭遇一次)



要明白这个问题,我们要知道new和new[],delete和delete[]都干什么了些什么。

不用多说new和delete。

1.new封装了C语言中的malloc 函数,申请一块内存空间,如果T是用户自定义的类类型,将使用T的构造函数初始化这块内存空间上的对象。

2.delete封装了C语言中的free 函数,如果T是用户自定义的类类型,首先调用T的析构函数,再调用free释放这个对象占用的内存空间。

new[]会更复杂一些:

T* ptr = new  T [1024];
delete[] ptr;

我们注意到,没有传入任何关于ptr指针的信息给delete[]操作符运算符(operator)。最初的C++编译器版本是要求程序员传入关于指针指向空间的大小的参数,而现代的编译器虽然也接受,但多数情况会忽视它[1]!

既然没有传入参数,那编译器一定是通过某种手段获知ptr指向空间的大小。

是的,说某种手段,是因为有多种方法。在C++发展的最初,有一种关联数组的方法:T* ptr = new[s]申请一段空间后,编译器会在内存的某个地方固定的数组中存入ptr和ptr对应的空间大小s,下次在调用delete[]的时候,就会查找这个数组中的ptr对应的s。[2]

这个方法,现代的编译器已经很少见了,因为它很慢。

现代的g++、vc、icpc都使用信息头(additional information head block)的方法来管理。在new[]申请内存空间时,会多申请n个字节,这n个字节就是信息头,位于我们ptr指针向低地址偏移n个字节的地方(block = ptr - n)。每次delete[]被调用时,编译器就会去这个信息头查找申请的内存信息。

所以,调用new[]得到的东西和调用malloc得到的东西并不相同!

现在,我们分析一下

A* ptr = new A [1024];

delete ptr;

这段代码在delete的时候发生了什么:

首先,和delete任何时候一样,编译器会给delete指派A的析构函数,以函数指针的形式,delete会调用这个析构函数,作用于ptr指向的这个对象上,显然ptr之后的1023个对象不会调用析构函数,因为我们使用的是delete而不是delete[]。然后,delete执行free函数,释放申请的空间。

但是!我们new[]中调用malloc得到的指针并不是从ptr开始的,我们的程序找不到malloc分配的ptr指针,就会崩溃![3]

而为什么base type不会有问题呢?程序运行得好好的。是的,都是编译器的原因。编译器检查到,如果是base tyep,new[]操作就会省去前面的信息头,后面发生delete释放new[]的时候,free调用的ptr和malloc调用的ptr也就一致了。当然,这不一定,也有可能某些编译器,在某些时候,即便是base type它也要加上head block呢?!

所以,如果new和delete,new[]和delete[]不配对,发生什么,未定义!

看到这里,相信你已经明白了delete[]为什么要对应new[]了,而delete也不能和delete[]混用的原因。

有什么问题欢迎留言,交流。



[1][2]《深入探索C++对象模型》

[3]http://stackoverflow.com/questions/8940090/is-it-safe-on-linux-to-mix-new-and-delete    ”LiKao“ 的回答

时间: 2024-10-17 15:41:36

使用delete释放new[]的空间造成的错误分析的相关文章

mysql delete删除记录数据库空间不减少问题解决方法

记得在中学时学计算机时老师就告诉我delete删除记录只是给数据库中的记录加一个删除标识了,这样数据库空间并不是减少了,当时没想这么多,昨天发现一个数据库利用delete 删除之后容量没变,后来百度了一下发现了下面一站长分享的文件,写得非常的不错,整理一下给各位参考. 今天空间商告诉我数据库空间满了,检查了一下,发现网站用户行为记录数据表竟然占了20多MB.积累了半年了,该删除释放一下空间了.果断delete之后发现数据库空间竟然没少,虽然数据记录数是零. 原来这是因为删除操作后在数据文件中留下

C++:delete和delete[]释放内存的区别

C++告诉我们在回收用 new 分配的单个对象的内存空间的时候用 delete,回收用 new[] 分配的一组对象的内存空间的时候用 delete[].  关于 new[] 和 delete[],其中又分为两种情况:(1) 为基本数据类型分配和回收空间:(2) 为自定义类型分配和回收空间. 请看下面的程序. 复制代码 代码如下: #include <iostream>; using namespace std; class T { public: T() { cout << &qu

Oracle move和shrink释放高水位空间 (一)

move 和shrink 的共同点 1.收缩段 2.消除部分行迁移 3.消除空间碎片 4.使数据更紧密 一.shrink 语法: alter table TABLE_NAME shrink space [compact|cascate] segment shrink执行的两个阶段: 1.数据重组(compact): 通过一系列insert.delete操作,将数据尽量排列在段的前面.在这个过程中需要在表上加RX锁,即只在需要移动的行上加锁. 由于涉及到rowid的改变,需要enable row

delete删除记录数据库空间大小不减少问题

记得在大学时学计算机时老师就告诉我delete删除记录只是给数据库中的记录加一个删除标识了,这样数据库空间并不是减少了,当时没想这么多,昨天发现一个数据库利用delete 删除之后容量没变,后来百度了一下发现了下面一站长分享的文件,写得非常的不错,整理一下给各位参考.今天空间商告诉我数据库空间满了,检查了一下,发现网站用户行为记录数据表竟然占了20多MB.积累了半年了,该删除释放一下空间了.果断delete之后发现数据库空间竟然没少,虽然数据记录数是零. 原来这是因为删除操作后在数据文件中留下碎

升级Windows 10后释放C盘空间

相信大家在微软免费推送升级Windows 10浪潮中,大多数朋友都从Windows 7或Windows 8.1顺利升级到了Windows 10,对于那些原来C盘空间就捉襟见肘的人来说,升级过程中产生的较大的临时Windows 安装文件和升级文件,及旧版本文件,如果你想释放C盘空间,又不不想回滚到以前的操作系统,请按照如下步骤操作,让C盘空间回归. 一.右键C盘,属性,常规,点击"磁盘清理" 二.在磁盘清理窗口,点击"清理系统文件" 三.勾选你要删除的文件,点击&qu

New动态分配 Delete 释放内存

在C++中,对于变量和对象都是编译器在编译时分配好的,对于数组初始化时,无法确定多少内存,很容意造成大开小用的情况. new  动态分配 一般格式:1. 指针变量名 =new  类型标识符; 2.指针变量名  =new  类型标识符(初始值); 3.指针变量名  =new  类型标识符 [内存单元个数];   开辟数组的定义方法 new运算符返回的是一个指向所分配类型变量的指针. delete 释放内存 一般格式:1.delete p; 2.delete []p; 删除变量p的地址空间,释放in

更改虚拟内存文件存放位置释放系统盘可用空间2016-01-15

更改虚拟内存文件存放位置释放系统盘可用空间2016-01-15 问题描述: 系统盘可用空间不足,通过将系统盘的虚拟内存文件转移到非系统盘(如D盘),释放虚拟内存文件所占用的系统盘空间,增加系统盘的可用空间. 1.打开"我的电脑"--"工具"--"文件夹选项"--"查看"--"显示所有文件和文件夹",并取消选中"隐藏说保护的操作系统文件(推荐)"选项--"应用"--&q

释放C盘空间的27招优化技巧

主要讲讲Windows操作系统在C盘空间不足的情况下,我们可以通过那些具体手段来增加C盘空间. 1.打开"我的电脑"-"工具"-"文件夹选项"-"查看"-在"显示所有文件和文件夹"选项前打勾-"确定" 2.删除以下文件夹中的内容: x:\Documents and Settings\用户名\Cookies\下的所有文件(保留index文件) x:\Documents and Settin

Oracle—deallocate unused释放高水位空间(二)

deallocate unused :仅适用于释放HWM高水位以上的空间,而无法释放高水位以下的空间:比如对表预分配的空间 使用说明和方法,官方文档有说明,如下: Use the deallocate_unused_clause to explicitly deallocate unused space at the end of a database object segment and make the space available for other segments in the ta