这个问题一直困扰着我.我一直认为C++应该被设计成使"删除"操作符(没有括号)即使使用"new []"运算符也能工作.
在我看来,写这个:
int* p = new int;
应该相当于分配1个元素的数组:
int* p = new int[1];
如果这是真的,"删除"运算符可能总是删除数组,我们不需要"delete []"运算符.
是否有任何理由在C++中引入"delete []"运算符?我能想到的唯一原因是分配数组的内存占用量很小(你必须在某处存储数组大小),因此区分"delete"与"delete []"是一个很小的内存优化.
这样就可以调用各个元素的析构函数.是的,对于POD数组,没有太大区别,但在C++中,您可以拥有具有非平凡析构函数的对象数组.
现在,你的问题是,为什么不制造new
和delete
行为new[]
,delete[]
并摆脱new[]
和delete[]
?我会回到Stroustrup的"设计和演变"一书,他说如果你不使用C++功能,你就不应该为它们付费(至少在运行时).它现在的方式,a new
或delete
将表现得像malloc
和free
.如果delete
有了delete[]
意义,将有在运行时产生一些额外开销(如詹姆斯·柯伦指出).
该死的,我错过了整个问题,但我会将原来的答案作为旁注.为什么我们删除[]是因为很久以前我们删除了[cnt],即使今天你写了删除[9]或删除[cnt],编译器只是忽略了[]之间的东西但编译好了.那时,C++首先由前端处理,然后送到普通的C编译器.他们无法在窗帘下面的地方存储计数,也许他们当时甚至都想不到它.为了向后兼容,编译器最有可能使用[]之间给出的值作为数组的计数,如果没有这样的值,那么它们从前缀获得计数,因此它可以双向工作.后来,我们在[]和一切工作之间没有输入任何内容.今天,我不认为"删除[]"
我的原始答案(错过了重点)::
"删除"删除单个对象."delete []"删除对象数组.要使delete []起作用,实现将保留数组中的元素数.我只是通过调试ASM代码来仔细检查这一点.在我测试的实现(VS2005)中,计数被存储为对象数组的前缀.
如果在单个对象上使用"delete []",则count变量是垃圾,因此代码崩溃.如果对对象数组使用"delete",则由于某些不一致,代码会崩溃.我刚刚测试了这些案例!
"delete只删除为数组分配的内存." 另一个答案中的陈述是不对的.如果对象是类,则delete将调用DTOR.只需在DTOR代码中放置一个断点并删除该对象,断点就会命中.
我遇到的情况是,如果编译器和库假定"new"分配的所有对象都是对象数组,则可以为单个对象或对象数组调用"delete".单个对象就是一个数量为1的对象数组的特殊情况.也许有一些我缺少的东西,无论如何......
由于其他人似乎都错过了你的问题,我只想补充说,我在一年前就有同样的想法,而且从来没有得到答案.
我唯一能想到的是,将一个对象作为一个数组处理是一个非常微小的额外开销(一个不必要的" for(int i=0; i<1; ++i)
")
添加此,因为目前没有其他答案解决它:
数组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++中可用的内存管理选项的广度.