令我困扰的是delete []
实际上做了什么,所以我只是尝试了一些代码,我对结果感到震惊
测试#1:
int main()
{
int *d;
while(true)
{
d = new int[10];
delete []d;
}
}
程序根本不会消耗任何内存。
测试#2:
int main()
{
int *d;
while(true)
{
d = new int[10];
delete [](d + 5);
}
}
虽然在每个循环中都应该至少有20个字节(对于它保留在数组开头的五个整数)保留但未删除此程序也不会占用任何内存!
测试#3:
int main()
{
int *d;
while(true)
{
d = new int[10];
delete []d;
*d=1;
}
}
这个导致访问冲突按预期进行(似乎在delete []d
之后删除了所有内存。)
测试#4:
int main()
{
int *d;
while(true)
{
d = new int[10];
delete [](d+5);
*d=1;
}
}
这个是最令人惊讶的,虽然while不消耗任何内存,程序也不会产生任何访问冲突,我只是想知道* d在哪里存储它的数据?
(顺便说一下,所有程序都是使用no-optimization编译的!)
现在主要问题是:
如果我分配了一个数组并且我已经完成了一半的工作,那么我不能有机会释放那一半并保留另一半吗?
答案 0 :(得分:5)
令我困扰的是
delete []
实际上
你不应该担心delete[]
实际上做了什么。对于所有意图和目的而言,它是一个黑盒子,其中包含有关如何正确使用它的某些规则。您需要担心实际需要做的唯一一次是编写编译器或C ++运行时(例如操作系统等)
对于那些“如何正确使用它的某些规则”,测试#2和#4调用未定义的行为:
ISO C ++ 2003标准5.3.5删除[expr.delete]
1 delete-expression运算符会销毁由new-expression创建的派生程度最高的对象(1.8)或数组。
delete-expression:
::opt delete cast-expression
::opt delete [ ] cast-expression
第一种选择是非阵列 对象,第二个是数组。 操作数应具有指针类型, 或具有单一的类型 转换函数(12.3.2)到a 指针类型。结果有类型 空隙。
2 如果操作数有类类型,则 操作数转换为指针类型 通过调用上述内容 转换功能,并转换 操作数用于代替 原始操作数为剩余的 这个部分。无论哪种方式, 如果删除操作数的值 是操作具有的空指针 没有效果。在第一个替代方案中 (删除对象),值的 delete的操作数应为指针 到非数组对象或指向 表示基础的子对象(1.8) 这类物体的一类(第10条)。 如果不是,则行为未定义。 在第二个备选(删除数组)中,操作数的值 delete应为指针值 这是由前一个数组产生的 新的表达。如果没有,那就是 行为未定义。 [注意:这个 意味着的语法 delete-expression必须与类型匹配 由new分配的对象,而不是 new-expression的语法。 ]
“未定义的行为”意味着可能发生任何事情,包括您刚刚描述的行为。
您在测试#2和#4中使用的这些表达式违反了5.3.5 / 2并将导致未定义的行为(测试#3也会导致未定义的行为,但原因不同)。
d = new int[10];
delete [](d + 5);
delete[]
行违反了5.3.5 / 2,因为您传递给delete[]
的指针值与new int[]
给您的值不同。
因此,如果new int[]
命令为您提供0xA01D2CE9
并且您将0xA01D2CE9 + 5
传递给delete[]
,那么您无法推理或预测会发生什么,因为您打破了语言规则。实际发生的将取决于编译器和/或操作系统如何处理new[]
和delete[]
。这可以从任何错误发生到完全崩溃您的系统,以及介于两者之间的任何地方。
换句话说,就是不要写delete [](d + 5);
之类的东西。
答案 1 :(得分:2)
当你说“不消耗任何内存”时,你是在谈论在“任务管理器”风格的性能监视器中查看?因为如果是这样的话,40字节不会显示为“内存使用”......你将不得不为大多数标准流程性能监视器分配更多的内存。
答案 2 :(得分:1)
delete [](d + 5);
(来自你的测试#2)肯定是你应该不做的事情,如果不是段错误,这将破坏内存。它实际上是我平台上的段错误。
您的测试结果将取决于许多事情,其中包括您运行这些测试的平台,new/delete
的内部等。
答案 3 :(得分:1)
delete [](d + 5);
听起来你希望这只释放new int[10]
分配的部分内存。
情况并非如此,它会导致未定义的行为,并可能导致任何事情发生。
在某些内存管理器上,如果你要求它们通过传递一个指针释放一个块,如果你没有将指针传递给该块的开头,那么它们可以释放包含的整个块你传递的指针。在您的情况下可能会发生这种情况。
另一个考虑因素是new int[10]
没有初始化分配的内存,因此操作系统可以只分配一些地址空间,而不需要使用任何物理存储来支持分配。这意味着即使您在没有任何new int[10]
的循环中调用delete[]
,您也可能会在许多内存监视工具中看到内存使用率没有上升,甚至在new[]
抛出{std::bad_alloc
时也是如此。耗尽logicalbvg地址空间时出现异常。 (这可能需要花费一些时间才能一次分配10个字节。)
答案 4 :(得分:0)
您是否在发布版本下运行这些测试?你看过生成的装配说明了吗?你如何衡量内存消耗?你正在分配40个字节然后立即清除它。
此外,执行delete [](d + 5)
之类的操作会调用未定义的行为。您需要传入operator new
返回的指针才能使delete
正常工作。