【问题标题】:Why can't I delete other-than-first element from array by pointer为什么我不能通过指针从数组中删除第一个元素以外的元素
【发布时间】:2015-12-28 19:40:51
【问题描述】:

考虑以下代码:

int main()
{
  int *intArPtr = new int[100];
  int *intArPtr1 = intArPtr + 1;

  delete [] intArPtr; //ok
  //delete intArPtr; //valgrind warning, but no leaks!
  //delete intArPtr1; //invalid pointer error

  return 0;
}

我知道delete [] intArPtr 是删除此数组的唯一有效方法,但我只是对以下内容感到好奇:

  1. 为什么delete intArPtr 不会产生任何内存泄漏?是吗 未定义的行为,我很幸运没有任何行为?
  2. 为什么delete intArPtr1 在运行时出现错误?为什么它不从数组中删除除第一个元素之外的所有元素?
  3. C++ 的运行时如何知道分配数组的大小(对于 delete [])?它是否存储在某个地方?

【问题讨论】:

标签: c++ arrays memory-management memory-leaks heap-memory


【解决方案1】:
  1. 为什么删除 intArPtr 不会产生任何内存泄漏?这是未定义的行为,我很幸运没有吗?

是同时不是。使用delete 而不是delete[] 并不干净,但通常可以。基本上,指针和偏移量都在分配时存储。这允许在使用 delete 时发生正确的释放,即使是偶然的。

  1. 为什么删除 intArPtr1 会在运行时出现错误?为什么它不从数组中删除除第一个元素之外的所有元素?

intArPtr1与分配区域的指针不对应。当尝试delete 时,运行时在分配表中找不到该地址。

  1. C++ 的运行时如何知道分配数组的大小(对于 delete [])?它存储在某个地方吗?

它存储在分配表中,带有指向分配区域的指针。

【讨论】:

    【解决方案2】:
    1. 为什么delete intArPtr 不会产生任何内存泄漏?是吗 未定义的行为,我很幸运没有?

    正确,在分配有new[] 的内存上调用delete 是未定义的行为。一方面,它不会调用数组成员的析构函数。

    对于两个,即使您只是询问内存释放而不是对象销毁,deletedelete[] 也有可能实现相同或不同。它们读起来好像它们是同一个东西,但它们不是:deletedelete[] 是两个不同的运算符,具有可能不同的实现。他们可以使用不同的分配策略(请参阅下面问题 #3 的答案)。

    1. 为什么delete intArPtr1 在运行时出现错误?为什么它不从数组中删除除第一个元素之外的所有元素?

    你必须传递delete 一个用new 分配的指针。准确的指针。不是new 分配的内存区域内的指针,这是行不通的。它必须是指向区域开始的相同指针。

    1. C++ 的运行时如何知道分配数组的大小(对于 delete [])?它存储在某个地方吗?

    一种常见的分配器策略是在分配区域之前存储分配的字节数。 delete 然后将获取您传递给它的指针,向左看 4 或 8 个字节,并将该整数解释为区域的大小。如果你将一个指向其他地方的指针传递给它,它的回溯策略将会失败。

    C++ 语言没有指定如何跟踪内存分配,因此这是一个实现细节。不同的标准库、编译器和操作系统会以不同的方式执行此操作。我所描述的只是一种可能的机制。

    进一步阅读:

    【讨论】:

    • 这对我来说很清楚。谢谢!
    • deletedelete[] 不可能“实现相同”。对于 POD 类型,调用任何一个的效果可能无法区分,但对于包含指向被删除对象拥有的其他分配的指针的用户定义类型,调用 delete 和调用 delete[] 之间存在巨大差异,即使在错误使用它们对 POD 类型的影响无法区分的系统。关键问题是delete 将只为[0] 处的对象调用一次类型的析构函数,而delete[] 将为数组中的每个对象调用析构函数。
    • @phonetagger:deletedelete[] 的实现当然可以相同,例如,如果 new T 的实现与 new T[1] 具有相同的效果。跨度>
    【解决方案3】:

    答案:

    1. 您的示例中没有内存泄漏。事实上,删除没有 [] 的数组只会导致内存泄漏,如果数组中的对象自己分配了一些内存并且应该在析构函数中释放该内存。在所有其他情况下,不正确的删除不会导致内存泄漏。
    2. 因为分配的内存大小存储在指针之前。当您访问除第一个以外的数组的任何其他元素时,那里没有适当的内存大小。
    3. 见 2。

    【讨论】:

    • 1.这取决于实现 - 未定义的行为。
    猜你喜欢
    • 2021-11-28
    • 2018-11-04
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 2013-09-23
    • 2017-02-25
    • 2023-03-04
    • 1970-01-01
    相关资源
    最近更新 更多