C++ 当需要数组删除运算符时,为什么常规删除运算符可以工作?
我最近发现代码中的很多地方都在做这样的事情:C++ 当需要数组删除运算符时,为什么常规删除运算符可以工作?,c++,visual-c++,clang,C++,Visual C++,Clang,我最近发现代码中的很多地方都在做这样的事情: int * int_array = new int[1000]; // ... do things with int_array delete int_array; 当然,问题是它应该使用delete[]操作符,而不是常规的delete操作符 神秘的是:当Visual Studio 2003和2005在Windows上编译,而GCC/clang在OS X上编译时,这段代码已经工作了好几年了。为什么这之前没有导致严重的错误呢 据我所知,我们告诉编
int * int_array = new int[1000];
// ... do things with int_array
delete int_array;
当然,问题是它应该使用delete[]
操作符,而不是常规的delete
操作符
神秘的是:当Visual Studio 2003和2005在Windows上编译,而GCC/clang在OS X上编译时,这段代码已经工作了好几年了。为什么这之前没有导致严重的错误呢
据我所知,我们告诉编译器以“错误”的方式释放内存,如果这样做,通常会发生可怕的事情,程序崩溃。为什么我们没有这样做?现代编译器是否会自动为您“做正确的事情”,或者是否足够做正确的事情,以至于对基本类型不重要?我不能接受我们只是运气好,因为这段代码已经被成千上万的客户在多个不同的操作系统下使用了多年
请注意,我并不是要找一个做错事情的借口,只是想理解为什么我们不会因为做错事情而陷入麻烦 这不起作用。删除不带
[]
的阵列将泄漏内存。如果应用程序长时间运行,将影响性能。对于短命的项目,不会有任何问题
另一件需要注意的事情是
delete
将销毁new
分配的所有内存。如果您通过new
(而不是new[]
)分配了一个数组,您可以使用delete
销毁它 这不起作用。删除不带[]
的阵列将泄漏内存。如果应用程序长时间运行,将影响性能。对于短命的项目,不会有任何问题
另一件需要注意的事情是
delete
将销毁new
分配的所有内存。如果您通过new
(而不是new[]
)分配了一个数组,您可以使用delete
销毁它 这不会导致程序崩溃,但每次这样做时都会泄漏999*sizeof(int)
字节的内存。这不会导致程序崩溃,但会泄漏999*sizeof(int)
每次执行此操作时都会释放内存字节。常规的删除操作实际上可能会从数组中释放所有内存,具体取决于分配器,但真正的问题是它永远不会对数组元素运行任何析构函数。常规的删除操作实际上可能会从数组中释放所有内存,取决于分配器,但真正的问题是它永远不会在数组元素上运行任何析构函数。这是未定义行为的本质——它可能完全按照您的预期执行。问题是,下一版本的编译器、操作系统、库或CPU。。。它可能会做一些完全不同的事情
最有可能的是,由于两个原因,你侥幸逃脱了惩罚:
int
没有析构函数。因此,未能正确销毁阵列中的每个元素不会产生任何后果
在此平台上,new
和new[]
使用相同的分配器。因此,您没有将块返回给错误的分配器
这是未定义行为的本质——它可能完全按照您的意图执行。问题是,下一版本的编译器、操作系统、库或CPU。。。它可能会做一些完全不同的事情
最有可能的是,由于两个原因,你侥幸逃脱了惩罚:
int
没有析构函数。因此,未能正确销毁阵列中的每个元素不会产生任何后果
在此平台上,new
和new[]
使用相同的分配器。因此,您没有将块返回给错误的分配器
让我们一步一步地看看发生了什么(但我们将忽略异常):
这将为数组中的每个元素分配100*sizeof(int)
字节的内存,并调用int::int()
100次
由于int
是一种内置类型,因此它有一个简单的构造函数(即,它什么也不做)
现在,我们来看看:
delete foo;
这将对foo
指向的地址调用int::~int()
,然后删除foo
指向的内存。同样,由于int
是一个内置类型,因此它有一个简单的析构函数
将此与:
delete [] foo;
它将为foo
指向的数组中的每个项调用int::~int()
,然后删除foo指向的内存
这里的基本区别是元素1..99不会被破坏。对于int
,这不是问题,这可能就是现有代码工作的原因。对于具有真实析构函数的对象数组,您将看到更多的错误行为
注意:如果您编写delete foo,大多数实现将删除foo
指向的整个内存块代码>即使您为其分配了新的数组-但如果您指望它,那将是愚蠢的。让我们一步一步地了解发生了什么(但我们将忽略异常):
这将为数组中的每个元素分配100*sizeof(int)
字节的内存,并调用int::int()
100次
由于int
是一种内置类型,因此它有一个简单的构造函数(即,它什么也不做)
现在,我们来看看:
delete foo;
这将对foo
指向的地址调用int::~int()
,然后删除foo
指向的内存。同样,由于int
是一个内置类型,因此它有一个简单的析构函数
将此与:
delete [] foo;
它将为foo
指向的数组中的每个项调用int::~int()
,然后删除foo指向的内存