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

为什么我们甚至需要"delete []"运算符?

如何解决《为什么我们甚至需要"delete[]"运算符?》经验,为你挑选了4个好方法。

这个问题一直困扰着我.我一直认为C++应该被设计成使"删除"操作符(没有括号)即使使用"new []"运算符也能工作.

在我看来,写这个:

int* p = new int;

应该相当于分配1个元素的数组:

int* p = new int[1];

如果这是真的,"删除"运算符可能总是删除数组,我们不需要"delete []"运算符.

是否有任何理由在C++中引入"delete []"运算符?我能想到的唯一原因是分配数组的内存占用量很小(你必须在某处存储数组大小),因此区分"delete"与"delete []"是一个很小的内存优化.



1> David Nehme..:

这样就可以调用各个元素的析构函数.是的,对于POD数组,没有太大区别,但在C++中,您可以拥有具有非平凡析构函数的对象数组.

现在,你的问题是,为什么不制造newdelete行为new[],delete[]并摆脱new[]delete[]?我会回到Stroustrup的"设计和演变"一书,他说如果你不使用C++功能,你就不应该为它们付费(至少在运行时).它现在的方式,a newdelete将表现得像mallocfree.如果delete有了delete[]意义,将有在运行时产生一些额外开销(如詹姆斯·柯伦指出).


实际上,当你使用new int [1]时,它会在它的第一个数据之前存储在数组的头部,即它的大小.因此,使用delete而不是delete []将不会释放内存的那一部分.

2> Malkocoglu..:

该死的,我错过了整个问题,但我会将原来的答案作为旁注.为什么我们删除[]是因为很久以前我们删除了[cnt],即使今天你写了删除[9]或删除[cnt],编译器只是忽略了[]之间的东西但编译好了.那时,C++首先由前端处理,然后送到普通的C编译器.他们无法在窗帘下面的地方存储计数,也许他们当时甚至都想不到它.为了向后兼容,编译器最有可能使用[]之间给出的值作为数组的计数,如果没有这样的值,那么它们从前缀获得计数,因此它可以双向工作.后来,我们在[]和一切工作之间没有输入任何内容.今天,我不认为"删除[]"

我的原始答案(错过了重点)::

"删除"删除单个对象."delete []"删除对象数组.要使delete []起作用,实现将保留数组中的元素数.我只是通过调试ASM代码来仔细检查这一点.在我测试的实现(VS2005)中,计数被存储为对象数组的前缀.

如果在单个对象上使用"delete []",则count变量是垃圾,因此代码崩溃.如果对对象数组使用"delete",则由于某些不一致,代码会崩溃.我刚刚测试了这些案例!

"delete只删除为数组分配的内存." 另一个答案中的陈述是不对的.如果对象是类,则delete将调用DTOR.只需在DTOR代码中放置一个断点并删除该对象,断点就会命中.

我遇到的情况是,如果编译器和库假定"new"分配的所有对象都是对象数组,则可以为单个对象或对象数组调用"delete".单个对象就是一个数量为1的对象数组的特殊情况.也许有一些我缺少的东西,无论如何......



3> James Curran..:

由于其他人似乎都错过了你的问题,我只想补充说,我在一年前就有同样的想法,而且从来没有得到答案.

我唯一能想到的是,将一个对象作为一个数组处理是一个非常微小的额外开销(一个不必要的" for(int i=0; i<1; ++i)")



4> Aaron..:

添加此,因为目前没有其他答案解决它:

数组delete[]不能在指针到基类上使用 - 当编译器在调用时存储对象的数量时new[],它不存储对象的类型或大小(正如David指出的那样,在C++中你很少支付对于您没有使用的功能).但是,标量delete可以通过基类安全地删除,因此它用于正常对象清理和多态清理:

struct Base { virtual ~Base(); };
struct Derived : Base { };
int main(){
    Base* b = new Derived;
    delete b; // this is good

    Base* b = new Derived[2];
    delete[] b; // bad! undefined behavior
}

但是,在相反的情况下 - 非虚拟析构函数 - 标量delete应该尽可能便宜 - 它不应该检查对象的数量,也不应该检查被删除的对象的类型.这使得内置类型或普通旧数据类型的删除非常便宜,因为编译器只需要调用而不需要::operator delete其他内容:

int main(){
    int * p = new int;
    delete p; // cheap operation, no dynamic dispatch, no conditional branching
}

虽然不是对内存分配的详尽处理,但我希望这有助于阐明C++中可用的内存管理选项的广度.

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