是否需要在原始指针位置调用delete []

时间:2018-01-18 13:37:21

标签: c++ memory memory-management

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

  

您的分配器将跟踪您分配的内存量

  

如何自由知道释放多少内存“

     
    

是的,内存块大小由malloc存储在“某处”(通常在块本身中),这就是免费知道的。但是,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;
}

3 个答案:

答案 0 :(得分:8)

是的。如果您更改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

答案 1 :(得分:1)

您可能有兴趣知道新的和删除真正做了什么(获得一些许可,忽略异常和对齐):

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[]返回的指针。

答案 2 :(得分:0)

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

来自cppreference

  

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