I'm wondering specifically about the following situation (which I discovered in some code I have to work with):
我特别想知道以下情况(我在一些代码中发现了我必须使用的情况):
SomeClass *ar = new SomeClass[2];
ar++;
delete[] ar;
This code seems to be working fine - i.e. not crashing (win32, built with VS2005).
这段代码似乎运行正常 - 即没有崩溃(win32,使用VS2005构建)。
Is this "legal"? It certainly doesn't feel right.
这是“合法的”吗?当然感觉不对。
7 个解决方案
#1
21
No, it is undefined to pass any address to delete
which was not returned by new
.
Here is the quote from the Standard.
不,未定义传递任何未被new返回的地址。以下是标准的引用。
§ 3.7.4.2-3
If a deallocation function terminates by throwing an exception, the behavior is undefined. The value of the first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation function is one supplied in the standard library, the call has no effect. Otherwise, the value supplied to operator delete(void*)
in the standard library shall be one of the values returned by a previous invocation of either operator new(std::size_t)
or operator new(std::size_t, const std::nothrow_-t&)
in the standard library, and the value supplied to operator delete[](void*)
in the standard library shall be one of the values returned by a previous invocation of either operator new[](std::size_t)
or operator new[](std::size_t, const std::nothrow_t&)
in the standard library.
如果通过抛出异常终止释放函数,则行为未定义。提供给解除分配函数的第一个参数的值可以是空指针值;如果是这样,并且如果解除分配功能是标准库中提供的功能,则该呼叫无效。否则,标准库中提供给operator delete(void *)的值应该是前一次调用new(std :: size_t)或operator new(std :: size_t,const std ::)返回的值之一。 nothrow_-t&)在标准库中,并且标准库中提供给operator delete [](void *)的值应该是之前调用operator new [](std :: size_t)返回的值之一或者标准库中的operator new [](std :: size_t,const std :: nothrow_t&)。
#2
20
No, not legal. You can only delete
what you got back from new
, and the exact same applies to new[]
and delete[]
不,不合法。你只能删除你从新回来的东西,同样适用于new []和delete []
#3
7
No it is not. You must call delete[] on the very same address (or pointer) that you received from new[]. You might just get lucky that it does not crash, but it definitely does not clear the memory appropriately.
不它不是。您必须在从新[]收到的相同地址(或指针)上调用delete []。你可能只是幸运的是它没有崩溃,但它绝对不能恰当地清除内存。
References :
From http://www.cplusplus.com/doc/tutorial/dynamic/
The value passed as argument to delete must be either a pointer to a memory block
previously allocated with new, or a null pointer (in the case of a null pointer,
delete produces no effect).
From http://msdn.microsoft.com/en-us/library/h6227113.aspx
Using delete on a pointer to an object not allocated with new gives
unpredictable results. You can, however, use delete on a pointer with the
value 0. This provision means that, when new returns 0 on failure, deleting
the result of a failed new operation is harmless.
#4
6
From standard docs,. 5.3.5.2 Delete
,
来自标准文档。 5.3.5.2删除,
... In the second alternative (delete array), the value of the operand of delete shall be the pointer value which resulted from a previous array new-expression.72) If not, the behavior is undefined. ....
...在第二个备选(删除数组)中,delete的操作数的值应该是由前一个数组new-expression产生的指针值.72)如果不是,则行为是未定义的。 ....
Also the sub-note 72) states that,
分注72)还指出,
72)For non-zero-length arrays, this is the same as a pointer to the first element of the array created by that new-expression. Zero-length arrays do not have a first element.
72)对于非零长度数组,这与指向该new-expression创建的数组的第一个元素的指针相同。零长度数组没有第一个元素。
And so yes, it is undefined.
所以是的,它是未定义的。
#5
1
The standard states that you can only delete what you allocated with new, but that doesn't explain why it crashes, or in this case, doesn't crash.
该标准规定您只能删除使用new分配的内容,但这并不能解释崩溃的原因,或者在这种情况下不会崩溃。
When you delete a pointer, you are putting it back in the heap to be used again in future allocations. The typical implementation gives you a pointer, with an int just before your pointer tracking the memory in the block (that's the typical malloc implementation). Like this, for a typical 32 bit system.
删除指针时,将其放回堆中以便在将来的分配中再次使用。典型的实现为您提供了一个指针,在您的指针跟踪块中的内存之前使用int(这是典型的malloc实现)。像这样,对于典型的32位系统。
p-4 size here
p--> +--------+
| your |
| block |
So if you point into the middle of the block, it's going to interpret the bytes just before it as a size, with potentially disasterous results. You were saved from seeing the crash by your tiny code example. Probably, you never tried to allocate after that point. If you try to allocate something after that, it will probably crash, because it will try to recycle some of the memory you just gave back.
因此,如果你指向块的中间,它将把它之前的字节解释为一个大小,可能带来灾难性的结果。通过您的小代码示例,您可以免于看到崩溃。也许,在那之后你从未尝试过分配。如果你尝试在那之后分配一些东西,它可能会崩溃,因为它会尝试回收你刚才给出的一些内存。
The exact reason obviously depends on the implementation. This is just to explain one common way improper deletes can fail, not specifically verified for Visual Studio 2005.
确切的原因显然取决于实施。这只是为了解释不正确删除可能失败的一种常见方式,而不是针对Visual Studio 2005进行专门验证。
#6
0
It is not legal The fact that it does not crash does not mean it will not in other circumstances. It will surely crash if you enable verifier. And in any case it will not free your array. This is just the CRT / Windows letting your program not crash when it should
这是不合法的事实它不会崩溃并不意味着它不会在其他情况下。如果启用验证程序,它肯定会崩溃。无论如何它不会释放你的阵列。这只是CRT / Windows让你的程序不应该崩溃
#7
#1
21
No, it is undefined to pass any address to delete
which was not returned by new
.
Here is the quote from the Standard.
不,未定义传递任何未被new返回的地址。以下是标准的引用。
§ 3.7.4.2-3
If a deallocation function terminates by throwing an exception, the behavior is undefined. The value of the first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation function is one supplied in the standard library, the call has no effect. Otherwise, the value supplied to operator delete(void*)
in the standard library shall be one of the values returned by a previous invocation of either operator new(std::size_t)
or operator new(std::size_t, const std::nothrow_-t&)
in the standard library, and the value supplied to operator delete[](void*)
in the standard library shall be one of the values returned by a previous invocation of either operator new[](std::size_t)
or operator new[](std::size_t, const std::nothrow_t&)
in the standard library.
如果通过抛出异常终止释放函数,则行为未定义。提供给解除分配函数的第一个参数的值可以是空指针值;如果是这样,并且如果解除分配功能是标准库中提供的功能,则该呼叫无效。否则,标准库中提供给operator delete(void *)的值应该是前一次调用new(std :: size_t)或operator new(std :: size_t,const std ::)返回的值之一。 nothrow_-t&)在标准库中,并且标准库中提供给operator delete [](void *)的值应该是之前调用operator new [](std :: size_t)返回的值之一或者标准库中的operator new [](std :: size_t,const std :: nothrow_t&)。
#2
20
No, not legal. You can only delete
what you got back from new
, and the exact same applies to new[]
and delete[]
不,不合法。你只能删除你从新回来的东西,同样适用于new []和delete []
#3
7
No it is not. You must call delete[] on the very same address (or pointer) that you received from new[]. You might just get lucky that it does not crash, but it definitely does not clear the memory appropriately.
不它不是。您必须在从新[]收到的相同地址(或指针)上调用delete []。你可能只是幸运的是它没有崩溃,但它绝对不能恰当地清除内存。
References :
From http://www.cplusplus.com/doc/tutorial/dynamic/
The value passed as argument to delete must be either a pointer to a memory block
previously allocated with new, or a null pointer (in the case of a null pointer,
delete produces no effect).
From http://msdn.microsoft.com/en-us/library/h6227113.aspx
Using delete on a pointer to an object not allocated with new gives
unpredictable results. You can, however, use delete on a pointer with the
value 0. This provision means that, when new returns 0 on failure, deleting
the result of a failed new operation is harmless.
#4
6
From standard docs,. 5.3.5.2 Delete
,
来自标准文档。 5.3.5.2删除,
... In the second alternative (delete array), the value of the operand of delete shall be the pointer value which resulted from a previous array new-expression.72) If not, the behavior is undefined. ....
...在第二个备选(删除数组)中,delete的操作数的值应该是由前一个数组new-expression产生的指针值.72)如果不是,则行为是未定义的。 ....
Also the sub-note 72) states that,
分注72)还指出,
72)For non-zero-length arrays, this is the same as a pointer to the first element of the array created by that new-expression. Zero-length arrays do not have a first element.
72)对于非零长度数组,这与指向该new-expression创建的数组的第一个元素的指针相同。零长度数组没有第一个元素。
And so yes, it is undefined.
所以是的,它是未定义的。
#5
1
The standard states that you can only delete what you allocated with new, but that doesn't explain why it crashes, or in this case, doesn't crash.
该标准规定您只能删除使用new分配的内容,但这并不能解释崩溃的原因,或者在这种情况下不会崩溃。
When you delete a pointer, you are putting it back in the heap to be used again in future allocations. The typical implementation gives you a pointer, with an int just before your pointer tracking the memory in the block (that's the typical malloc implementation). Like this, for a typical 32 bit system.
删除指针时,将其放回堆中以便在将来的分配中再次使用。典型的实现为您提供了一个指针,在您的指针跟踪块中的内存之前使用int(这是典型的malloc实现)。像这样,对于典型的32位系统。
p-4 size here
p--> +--------+
| your |
| block |
So if you point into the middle of the block, it's going to interpret the bytes just before it as a size, with potentially disasterous results. You were saved from seeing the crash by your tiny code example. Probably, you never tried to allocate after that point. If you try to allocate something after that, it will probably crash, because it will try to recycle some of the memory you just gave back.
因此,如果你指向块的中间,它将把它之前的字节解释为一个大小,可能带来灾难性的结果。通过您的小代码示例,您可以免于看到崩溃。也许,在那之后你从未尝试过分配。如果你尝试在那之后分配一些东西,它可能会崩溃,因为它会尝试回收你刚才给出的一些内存。
The exact reason obviously depends on the implementation. This is just to explain one common way improper deletes can fail, not specifically verified for Visual Studio 2005.
确切的原因显然取决于实施。这只是为了解释不正确删除可能失败的一种常见方式,而不是针对Visual Studio 2005进行专门验证。
#6
0
It is not legal The fact that it does not crash does not mean it will not in other circumstances. It will surely crash if you enable verifier. And in any case it will not free your array. This is just the CRT / Windows letting your program not crash when it should
这是不合法的事实它不会崩溃并不意味着它不会在其他情况下。如果启用验证程序,它肯定会崩溃。无论如何它不会释放你的阵列。这只是CRT / Windows让你的程序不应该崩溃