【问题标题】:Does delete[] need to be called on the original pointer position是否需要在原始指针位置调用delete[]
【发布时间】:2018-06-27 14:34:56
【问题描述】:

根据这个问题的答案:“How does delete[] "know" the size of the operand array?

您的分配器将跟踪您分配了多少内存

free 知道要释放多少内存”

是的,内存块大小由 malloc 存储在“某处”(通常在块本身中),所以这就是 free 知道的。然而,new[]/delete[] 是另一回事。后者基本上在 malloc/free 之上工作。 new[] 还存储它在内存块中创建的元素数量(独立于 malloc),以便稍后 delete[] 可以检索并使用该数字来调用适当数量的析构函数

这是否意味着 delete[] 与指针指向的位置无关?以下代码是否有效还是会导致内存泄漏?

void createArray(){
    char* someArray = new char[20];
    readData(someArray);
    //Is this delete still valid after moving the pointer one position?
    delete[] someArray;
}

char readData(char* &arr){
    char value = *arr;
    //Let it point to the next element
    arr += 1;
    return value;
}

【问题讨论】:

  • 你的例子没有按照你的想法做,你的意思是写char readData(char*& arr) {...
  • readData 获取指针的副本;增量更改副本,但不影响原始值。无论如何,必须使用operator new[] 返回的值调用operator delete[]
  • @PeteBecker 现在它得到了参考! (OP 编辑​​)

标签: c++ memory memory-management


【解决方案1】:

是的。如果您更改 new[]-ed 指针值,然后在其上调用 delete[] 运算符,您将调用未定义的行为:

char* someArray = new char[20];
someArray++;
delete[] someArray; // undefined behavior

而是将原始值存储在不同的指针中并在其上调用delete[]

char* someArray = new char[20];
char* originalPointer = someArray;
someArray++; // changes the value but the originalPointer value remains the same
delete[] originalPointer; // OK

【讨论】:

  • 只是为了完全理解。在char* originalPointer = someArray; 行之后,两个指针相等。我还可以更改 originalPointer++ 并跟进 someArray 上的 delete[]。这是正确的吗?
  • 在那一行之后 - 两个指针相等。您可能不会在更改 originalPointer++ 时调用 delete[]。不要更改originalPointer 的值,因为我们需要它指向最初分配的内存区域。 someArray 的值可以更改,因为我们不会在其上调用运算符 delete[]
【解决方案2】:

您可能有兴趣了解 new 和 delete 在幕后的真正作用(取得一些许可,忽略异常和对齐):

template<class Thing>
Thing* new_array_of_things(std::size_t N)
{
  std::size_t size = (sizeof(Thing) * N) + sizeof(std::size_t);
  void* p = std::malloc(size);
  auto store_p = reinterpret_cast<std::size_t*>(p);
  *store_p = N;
  auto first = reinterpret_cast<Thing*>(store_p + 1);
  auto last = first + N;
  for (auto i = first ; i != last; ++i)
  {
    new (i) Thing ();
  }
  return first;  
}

template<class T>
void delete_array_of_things(Thing* first)
{
    if (first)
    {
        auto store_p = reinterpret_cast<std::size_t*>(first) - 1;
        auto N = *store_p;
        while (N--)
        {
            (first + N)->~Thing();
        }
        std::free(store_p);
    }
}

总结:

给你的指针不是指向分配内存开头的指针。数组的大小存储在为对象数组提供存储的内存之前(掩盖了一些细节)。

delete[] 理解这一点,并希望您提供new[] 返回的指针或其副本。

【讨论】:

  • 根据:stackoverflow.com/a/47771835/2393593 您可以在非原始指针上使用 delete[]。根据链接的答案,您不需要“提供相同的指针”。你这么说是什么意思?我因此而感到困惑。您说的是“相同的指针”,因为它不应该在地址中向前移动?
  • @Morfidon 也许我应该说相同的指针或它的副本。
【解决方案3】:

一般规则是您只能删除从new 获得的指针。在非数组版本中,您可以将指针传递给使用new 创建的基类子对象(授予基类具有虚拟析构函数)。如果是数组版本,它必须是相同的指针。

来自cppreference

对于第二种(数组)形式,表达式必须是空指针值或先前通过new-expression的数组形式获得的指针值。如果 expression 是其他任何东西,包括如果它是通过 new-expression 的非数组形式获得的指针,则行为未定义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-06
    • 1970-01-01
    • 2012-04-12
    • 1970-01-01
    • 2016-11-30
    • 2021-09-27
    • 1970-01-01
    相关资源
    最近更新 更多