我特别想知道以下情况(我在一些代码中发现了我必须使用的情况):
SomeClass *ar = new SomeClass[2];
ar++;
delete[] ar;
此代码似乎工作正常 - 即没有崩溃(win32,使用VS2005构建)。
这是“合法的”吗?当然感觉不对。
答案 0 :(得分:21)
不,未定义将delete
的任何地址传递给new
。
以下是标准的引用。
§3.7.4.2-3
如果通过抛出异常终止释放函数,则行为未定义。提供给解除分配函数的第一个参数的值可以是空指针值;如果是这样,并且如果解除分配功能是标准库中提供的功能,则该呼叫无效。否则,提供的值
标准库中的运算符delete(void*)
应该是先前调用标准库中的运算符new(std::size_t)
或operator new(std::size_t, const std::nothrow_-t&)
返回的值之一,并且值提供给运算符{{1标准库中的标签库应该是前一次调用delete[](void*)
或者返回的值之一
标准库中的operator new[](std::size_t)
。
答案 1 :(得分:20)
不,不合法。您只能delete
从new
获得的内容,new[]
和delete[]
答案 2 :(得分:7)
不,不是。您必须在从新[]收到的相同地址(或指针)上调用delete []。你可能只是幸运的是它没有崩溃,但它肯定不能恰当地清除内存。
参考文献:
来自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).
来自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.
答案 3 :(得分:6)
来自标准文档。 5.3.5.2 Delete
,
......在第二个 替换(删除数组),delete的操作数的值应该是由前一个产生的指针值 array new-expression.72)如果不是,则行为未定义。 ....
子注释 72)表明,
72)对于非零长度数组,这与指向该new-expression创建的数组的第一个元素的指针相同。零长度数组没有 有第一个元素。
所以是的,它是未定义的。
答案 4 :(得分:1)
该标准规定您只能删除使用new分配的内容,但这并不能解释崩溃原因,或者在这种情况下不会崩溃。
当您删除指针时,您将其放回堆中以便在将来的分配中再次使用。 典型的实现为您提供了一个指针,在您的指针跟踪块中的内存之前使用int(这是典型的malloc实现)。像这样,对于典型的32位系统。
p-4 size here
p--> +--------+
| your |
| block |
因此,如果你指向块的中间,它将把它之前的字节解释为一个大小,可能带来灾难性的结果。通过您的小代码示例,您可以免于看到崩溃。也许,在那之后你从未尝试过分配。如果你尝试在那之后分配一些东西,它可能会崩溃,因为它会尝试回收你刚刚给回的一些内存。
确切的原因显然取决于实施。这只是为了解释不正确删除可能失败的一种常见方式,而不是针对Visual Studio 2005进行专门验证。
答案 5 :(得分:0)
这是不合法的事实它不会崩溃并不意味着它不会在其他情况下。如果启用验证程序,它肯定会崩溃。无论如何它不会释放你的阵列。这只是CRT / Windows让你的程序在它应该
时不会崩溃答案 6 :(得分:0)