C++ delete[] 如何知道它是一个数组?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/703691/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does delete[] know it's an array?
提问by GRB
Alright, I think we all agree that what happens with the following code is undefined, depending on what is passed,
好吧,我想我们都同意以下代码发生的事情是未定义的,这取决于传递的内容,
void deleteForMe(int* pointer)
{
delete[] pointer;
}
The pointer could be all sorts of different things, and so performing an unconditional delete[]
on it is undefined. However, let's assume that we are indeed passing an array pointer,
指针可以是各种不同的东西,因此对其执行无条件delete[]
是未定义的。然而,让我们假设我们确实传递了一个数组指针,
int main()
{
int* arr = new int[5];
deleteForMe(arr);
return 0;
}
My question is, in this case where the pointer isan array, who is it that knows this? I mean, from the language/compiler's point of view, it has no idea whether or not arr
is an array pointer versus a pointer to a single int. Heck, it doesn't even know whether arr
was dynamically created. Yet, if I do the following instead,
我的问题是,在这种情况下,指针是一个数组,谁知道这一点?我的意思是,从语言/编译器的角度来看,它不知道arr
是数组指针还是指向单个 int 的指针。哎呀,它甚至不知道是否arr
是动态创建的。但是,如果我改为执行以下操作,
int main()
{
int* num = new int(1);
deleteForMe(num);
return 0;
}
The OS is smart enough to only delete one int and not go on some type of 'killing spree' by deleting the rest of the memory beyond that point (contrast that with strlen
and a non-\0
-terminated string -- it will keep going until it hits 0).
操作系统足够聪明,可以只删除一个 int 而不会通过删除超出该点的其余内存来进行某种类型的“杀戮狂欢”(与strlen
和非\0
终止字符串相比 - 它会一直持续到它命中 0)。
So whose job is it to remember these things? Does the OS keep some type of record in the background? (I mean, I realise that I started this post by saying that what happens is undefined, but the fact is, the 'killing spree' scenario doesn't happen, so therefore in the practical world someoneis remembering.)
那么记住这些东西是谁的工作呢?操作系统是否在后台保留某种类型的记录?(我的意思是,我意识到我开始这篇文章时说发生的事情是未定义的,但事实是,“杀人狂”场景不会发生,因此在实际世界中有人记得。)
采纳答案by Fred Larson
The compiler doesn't know it's an array, it's trusting the programmer. Deleting a pointer to a single int
with delete []
would result in undefined behavior. Your second main()
example is unsafe, even if it doesn't immediately crash.
编译器不知道它是一个数组,它信任程序员。删除指向单个int
with的指针delete []
会导致未定义的行为。你的第二个main()
例子是不安全的,即使它没有立即崩溃。
The compiler does have to keep track of how many objects need to be deleted somehow. It may do this by over-allocating enough to store the array size. For more details, see the C++ Super FAQ.
编译器确实必须跟踪需要以某种方式删除多少对象。它可以通过过度分配足够的空间来存储数组大小来做到这一点。有关更多详细信息,请参阅C++ 超级常见问题解答。
回答by Dan Breslau
One question that the answers given so far don't seem to address: if the runtime libraries (not the OS, really) can keep track of the number of things in the array, then why do we need the delete[]
syntax at all? Why can't a single delete
form be used to handle all deletes?
到目前为止给出的答案似乎没有解决一个问题:如果运行时库(不是操作系统,真的)可以跟踪数组中的事物数量,那么我们为什么需要delete[]
语法?为什么不能使用单个delete
表单来处理所有删除?
The answer to this goes back to C++'s roots as a C-compatible language (which it no longer really strives to be.) Stroustrup's philosophy was that the programmer should not have to pay for any features that they aren't using. If they're not using arrays, then they should not have to carry the cost of object arrays for every allocated chunk of memory.
这个问题的答案可以追溯到 C++ 作为 C 兼容语言的根源(它不再真正努力成为这种语言)。 Stroustrup 的理念是程序员不应该为他们没有使用的任何功能付费。如果他们不使用数组,那么他们就不必为每个分配的内存块承担对象数组的成本。
That is, if your code simply does
也就是说,如果您的代码只是
Foo* foo = new Foo;
then the memory space that's allocated for foo
shouldn't include any extra overhead that would be needed to support arrays of Foo
.
那么分配给的内存空间foo
不应包含支持Foo
.
Since only array allocations are set up to carry the extra array size information, you then need to tell the runtime libraries to look for that information when you delete the objects. That's why we need to use
由于只设置了数组分配来携带额外的数组大小信息,因此您需要告诉运行时库在删除对象时查找该信息。这就是为什么我们需要使用
delete[] bar;
instead of just
而不仅仅是
delete bar;
if bar is a pointer to an array.
如果 bar 是指向数组的指针。
For most of us (myself included), that fussiness about a few extra bytes of memory seems quaint these days. But there are still some situations where saving a few bytes (from what could be a very high number of memory blocks) can be important.
对于我们大多数人(包括我自己)来说,现在对一些额外的内存字节的挑剔似乎很古怪。但是在某些情况下,节省几个字节(从可能是非常多的内存块中)可能很重要。
回答by bsdfish
Yes, the OS keeps some things in the 'background.' For example, if you run
是的,操作系统在“背景”中保留了一些东西。例如,如果您运行
int* num = new int[5];
the OS can allocate 4 extra bytes, store the size of the allocation in the first 4 bytes of the allocated memory and return an offset pointer (ie, it allocates memory spaces 1000 to 1024 but the pointer returned points to 1004, with locations 1000-1003 storing the size of the allocation). Then, when delete is called, it can look at 4 bytes before the pointer passed to it to find the size of the allocation.
操作系统可以额外分配 4 个字节,将分配的大小存储在分配内存的前 4 个字节中,并返回一个偏移指针(即它分配了 1000 到 1024 的内存空间,但指针返回指向 1004,位置为 1000- 1003 存储分配的大小)。然后,当调用 delete 时,它可以查看传递给它的指针之前的 4 个字节,以找到分配的大小。
I am sure that there are other ways of tracking the size of an allocation, but that's one option.
我确信还有其他方法可以跟踪分配的大小,但这是一种选择。
回答by JaredPar
This is very similar to thisquestion and it has many of the details your are looking for.
这与这个问题非常相似,它包含您正在寻找的许多细节。
But suffice to say, it is not the job of the OS to track any of this. It's actually the runtime libraries or the underlying memory manager that will track the size of the array. This is usually done by allocating extra memory up front and storing the size of the array in that location (most use a head node).
但可以说,跟踪任何这些都不是操作系统的工作。实际上是运行时库或底层内存管理器将跟踪数组的大小。这通常是通过预先分配额外的内存并将数组的大小存储在该位置(大多数使用头节点)来完成的。
This is viewable on some implementations by executing the following code
这可以通过执行以下代码在某些实现上查看
int* pArray = new int[5];
int size = *(pArray-1);
回答by Beno?t
delete
or delete[]
would probably both free the memory allocated (memory pointed), but the big difference is that delete
on an array won't call the destructor of each element of the array.
delete
或者delete[]
可能都释放分配的内存(指向内存),但最大的区别是delete
在数组上不会调用数组的每个元素的析构函数。
Anyway, mixing new/new[]
and delete/delete[]
is probably UB.
不管怎样,混合new/new[]
和delete/delete[]
可能UB。
回答by eduffy
It doesn't know it's an array, that's why you have to supply delete[]
instead of regular old delete
.
它不知道它是一个数组,这就是为什么你必须提供delete[]
而不是常规的 old delete
。
回答by ProdigySim
I had a similar question to this. In C, you allocate memory with malloc() (or another similar function), and delete it with free(). There is only one malloc(), which simply allocates a certain number of bytes. There is only one free(), which simply takes a pointer as it's parameter.
我有一个类似的问题。在 C 中,您使用 malloc()(或其他类似函数)分配内存,并使用 free() 删除它。只有一个 malloc(),它只是分配一定数量的字节。只有一个 free(),它只需要一个指针作为它的参数。
So why is it that in C you can just hand over the pointer to free, but in C++ you must tell it whether it's an array or a single variable?
那么为什么在 C 中你可以直接将指针交给 free,而在 C++ 中你必须告诉它它是一个数组还是一个单个变量?
The answer, I've learned, has to do with class destructors.
我了解到,答案与类析构函数有关。
If you allocate an instance of a class MyClass...
如果你分配一个类 MyClass 的实例......
classes = new MyClass[3];
And delete it with delete, you may only get the destructor for the first instance of MyClass called. If you use delete[], you can be assured that the destructor will be called for all instances in the array.
并用 delete 删除它,您可能只会得到调用的 MyClass 的第一个实例的析构函数。如果使用delete[],则可以确保将为数组中的所有实例调用析构函数。
THIS is the important difference. If you're simply working with standard types (e.g. int) you won't really see this issue. Plus, you should remember that behavior for using delete on new[] and delete[] on new is undefined--it may not work the same way on every compiler/system.
这是重要的区别。如果您只是使用标准类型(例如 int),您将不会真正看到这个问题。另外,您应该记住,在 new[] 上使用 delete 和在 new 上使用 delete[] 的行为是未定义的——它在每个编译器/系统上的工作方式可能不同。
回答by Avt
ONE OF THE approaches for compilers is to allocate a little more memory and store count of elements in the head element.
编译器的一种方法是分配更多内存并在头元素中存储元素计数。
Example how it could be done: Here
示例如何完成:这里
int* i = new int[4];
compiler will allocate sizeof(int)*5 bytes.
编译器将分配 sizeof(int)*5 字节。
int *temp = malloc(sizeof(int)*5)
Will store 4
in first sizeof(int)
bytes
将存储4
在第一个sizeof(int)
字节中
*temp = 4;
and set i
并设置 i
i = temp + 1;
So i
points to array of 4 elements, not 5.
所以i
指向 4 个元素的数组,而不是 5 个。
And
和
delete[] i;
will be processed following way
将按照以下方式处理
int *temp = i - 1;
int numbers_of_element = *temp; // = 4
... call destructor for numbers_of_element elements if needed
... that are stored in temp + 1, temp + 2, ... temp + 4
free (temp)
回答by Uri
It's up to the runtime which is responsible for the memory allocation, in the same way that you can delete an array created with malloc in standard C using free. I think each compiler implements it differently. One common way is to allocate an extra cell for the array size.
这取决于负责内存分配的运行时,就像您可以使用 free 删除在标准 C 中使用 malloc 创建的数组一样。我认为每个编译器都以不同的方式实现它。一种常见的方法是为数组大小分配一个额外的单元格。
However, the runtime is not smart enough to detect whether or not it is an array or a pointer, you have to inform it, and if you are mistaken, you either don't delete correctly (E.g., ptr instead of array), or you end up taking an unrelated value for the size and cause significant damage.
但是,运行时不够智能,无法检测它是数组还是指针,您必须通知它,如果您弄错了,您要么没有正确删除(例如,ptr 而不是数组),要么您最终会为大小取一个无关的值并造成重大损坏。
回答by mloskot
Semantically, both versions of delete operator in C++ can "eat" any pointer; however, if a pointer to a single object is given to delete[]
, then UB will result, meaning anything may happen, including a system crash or nothing at all.
从语义上讲,C++ 中两个版本的 delete 运算符都可以“吃掉”任何指针;但是,如果将指向单个对象的指针提供给delete[]
,则将导致 UB,这意味着任何事情都可能发生,包括系统崩溃或什么也没有。
C++ requires the programmer to choose the proper version of the delete operator depending on the subject of deallocation: array or single object.
C++ 要求程序员根据释放的主题选择适当版本的删除运算符:数组或单个对象。
If the compiler could automatically determine whether a pointer passed to the delete operator was a pointer array, then there would be only one delete operator in C++, which would suffice for both cases.
如果编译器可以自动确定传递给 delete 运算符的指针是否是指针数组,那么 C++ 中将只有一个 delete 运算符,这对两种情况都足够了。