当前位置:  开发笔记 > 编程语言 > 正文

delete []如何知道它是一个数组?

如何解决《delete[]如何知道它是一个数组?》经验,为你挑选了7个好方法。

好吧,我想我们都同意以下代码所发生的事情是未定义的,具体取决于传递的内容,

void deleteForMe(int* pointer)
{
     delete[] pointer;
}

指针可以是各种不同的东西,因此delete[]对它执行无条件是未定义的.但是,让我们假设我们确实传递了一个数组指针,

int main()
{
     int* arr = new int[5];
     deleteForMe(arr);
     return 0;
}

我的问题是,在这种情况下,指针一个数组,谁知道这个?我的意思是,从语言/编译器的角度来看,它不知道arr数组指针是否指向单个int的指针.哎呀,它甚至不知道是否arr是动态创建的.但是,如果我做以下事情,

int main()
{
     int* num = new int(1);
     deleteForMe(num);
     return 0;
}

操作系统足够聪明,只能删除一个int,而不是通过删除超出该点的其余内存来进行某种类型的"杀戮狂欢"(与strlen\0终结字符串形成对比- 它将一直持续到它点击0).

那么他们的工作是记住这些东西吗?操作系统是否在后台保留某种类型的记录?(我的意思是,我意识到我开始这篇文章时说过发生的事情是未定义的,但事实是,'杀戮狂欢'的情况不会发生,所以因此在实际世界中有人记得.)



1> Dan Breslau..:

到目前为止给出的答案似乎没有解决的一个问题是:如果运行时库(不是OS,真的)可以跟踪数组中的事物数量,那么为什么我们需要delete[]语法呢?为什么不能使用单个delete表单来处理所有删除?

对此的回答可以追溯到C++作为C兼容语言的根源(它不再是真正的努力.)Stroustrup的理念是程序员不应该为他们没有使用的任何功能付费.如果他们不使用数组,那么他们不应该为每个分配的内存块承担对象数组的成本.

也就是说,如果您的代码只是这样做

Foo* foo = new Foo;

那么分配的内存空间foo不应包括支持数组所需的任何额外开销Foo.

由于只设置了数组分配来携带额外的数组大小信息,因此您需要告诉运行时库在删除对象时查找该信息.这就是我们需要使用的原因

delete[] bar;

而不仅仅是

delete bar;

如果bar是指向数组的指针.

对于我们大多数人(包括我自己)来说,关于几个额外字节的内存的烦恼现在看起来很古怪.但是仍然存在一些情况,即保存几个字节(从可能是非常多的内存块)可能很重要.


"对于一些额外的内存字节来说,这些日子看起来很古怪".幸运的是,对于这样的人来说,裸阵列也开始看起来很古怪,所以他们可以只使用vector或boost :: array,而忘记delete []永远:-)

2> Fred Larson..:

编译器不知道它是一个数组,它信任程序员.删除指向一个单一的intdelete []将导致不确定的行为.你的第二个main()例子是不安全的,即使它没有立即崩溃.

编译器必须跟踪需要以某种方式删除的对象数.它可以通过过度分配来存储数组大小来实现.有关更多详细信息,请参阅C++ Super FAQ.


@Rodrigo您的评论中的链接已被破坏,但幸运的是,该返回机器的副本位于http://replay.web.archive.org/20080703153358/http://taossa.com/index.php/2007/01/03 /攻击,删除和 - 删除 - 在-C
实际上,使用delete []删除使用new创建的内容是可利用的.http://taossa.com/index.php/2007/01/03/attacking-delete-and-delete-in-c/#comment-63884

3> bsdfish..:

是的,操作系统会在"背景"中保留一些内容.例如,如果你跑

int* num = new int[5];

操作系统可以分配4个额外字节,在分配的内存的前4个字节中存储分配的大小并返回偏移指针(即,它分配内存空间1000到1024但指针返回指向1004,位置1000- 1003存储分配的大小).然后,当调用delete时,它可以在指针传递给它之前查看4个字节以查找分配的大小.

我确信还有其他方法可以跟踪分配的大小,但这是一种选择.


+1 - 一般有效点,但通常语言运行时负责存储此元数据,而不是OS.
不,sizeof只显示数组的大小.*如果*运行时选择使用我描述的方法实现它,那严格来说是一个实现细节,从用户的角度来看,应该被屏蔽.指针之前的内存不属于用户,并且不会被计数.
更重要的是,在任何情况下,sizeof都不会返回动态分配的数组的真实大小.它只能返回编译时已知的大小.

4> JaredPar..:

这与此问题非常相似,它有许多您正在寻找的细节.

但足以说明,追踪任何此类操作系统并不是操作系统的工作.它实际上是运行时库或底层内存管理器,它们将跟踪数组的大小.这通常通过预先分配额外内存并将阵列的大小存储在该位置(大多数使用头节点)来完成.

通过执行以下代码,可以在某些实现中查看

int* pArray = new int[5];
int size = *(pArray-1);



5> Benoît..:

delete或者delete[]可能都释放分配的内存(内存指向),但最大的区别是delete数组上不会调用数组中每个元素的析构函数.

无论如何,混合new/new[],delete/delete[]可能是UB.



6> eduffy..:

它不知道它是一个数组,这就是为什么你必须提供delete[]而不是常规的旧delete.



7> ProdigySim..:

我有一个类似的问题.在C中,使用malloc()(或其他类似函数)分配内存,并使用free()将其删除.只有一个malloc(),它只分配一定数量的字节.只有一个free(),它只是将一个指针作为它的参数.

那么为什么在C中你可以将指针移交给free,但是在C++中你必须告诉它它是一个数组还是一个变量?

我已经知道,答案与类析构函数有关.

如果你分配一个MyClass类的实例...

classes = new MyClass[3];

并使用delete删除它,您可能只获得调用的MyClass的第一个实例的析构函数.如果使用delete [],则可以确保将为数组中的所有实例调用析构函数.

这是重要的区别.如果你只是使用标准类型(例如int),你将不会真正看到这个问题.另外,你应该记住在new []和delete []上使用delete的行为是未定义的 - 它可能在每个编译器/系统上的工作方式不同.

推荐阅读
放ch养奶牛
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有