【问题标题】:In what order should memory be deallocated in c++?在 C++ 中应该按什么顺序释放内存?
【发布时间】:2019-10-09 13:18:33
【问题描述】:

在 C++ 中使用 delete 运算符时,我很难理解正确的事件顺序。我已经内化了使用它的正确方法是当指针仍在引用指针时。

在下面的示例中 - 我将数组的内容复制到 temp 中,然后将 delete [] 复制到我的 arrayPointer 指向的旧数组中。

然后我将arrayPointer 指向新创建的数组并将不再需要的temp 设置为nullptr。我想通过不删除临时指针来确保不会导致内存泄漏。这还需要发生吗?

我之所以这么问,是因为我看到过我们先指向 nullptr 然后指向 delete 的示例,但这似乎违反直觉。任何指导将不胜感激。谢谢!

    template <class T>
    void ValSet<T>::add(T elementToAdd){
        if(!this->contains(elementToAdd)){

            if(sizeOfArray == numOfElements){
                sizeOfArray *= 2;
                T* temp = new T[sizeOfArray];
                for (int i = 0; i < numOfElements; i++)
                    temp[i] = arrayPointer[i];
                delete [] arrayPointer;
                arrayPointer = temp;
                temp = nullptr;
            }
        numOfElements += 1;
        arrayPointer[numOfElements-1] = elementToAdd;
        }
      }

【问题讨论】:

  • 您的代码在我看来没问题。 temp = nullptr; 是不必要但无害的; temp 很快就会超出范围。
  • 旁注,我想你想要`delete arrayPointer`而不是delete [] arrayPointer。
  • @Chipster - 这真的很有趣,但有点道理。成员 var 是指向 T 的指针,但是当构造 ValSet 对象时,arrayPointer 会创建一个新数组 - 那么 delete 是否适用于该上下文中的指针本身或创建的新数组?
  • @Chipster 假设 arrayPointer 的分配方式相同(应该是,无论是以前在 add 中分配还是任何其他调整大小的方法),那么 delete [] arrayPointer 是正确的方式销毁对象并释放内存。 (more details here)
  • @T.j.Banghart 有一个缺陷。如果new[] 抛出异常,sizeOfArray 现在有错误的值,而不是抛出异常之前的原始值。在调用new[] 之前,您需要恢复(或不更改)对象的状态。我假设sizeOfArray 是一个成员变量。

标签: c++ arrays pointers dynamic delete-operator


【解决方案1】:

正如您帖子中的 cmets 所指出的,您的解决方案是正确的。

为了更详细地解释您的正确原因,您确保在复制和删除当前数据之前分配了更多内存。这是唯一的顺序:保留(新数组)、复制、取消保留(旧数组)。 (反正我就是这么记的。)

更详细地说:temp 是一个指针,而不是数组本身。这是一个非常关键且经常被误解的观点。就个人而言,我为此付出了很多努力。因此,当您简单地说T* temp; 时,您正在为当前帧中的指针分配空间。当您说T* temp = new T[size]; 时,您是在为当前帧中的指针分配空间,并在内存中的其他地方请求更多空间(等于sizeof(T) * size 字节)。

这意味着temp作为一个指针是一个局部变量,但它指向的不是。当您分配arrayPointer = temp; 时,您是在说您的数据成员指向temp 指向的位置,但它不等于temp,因为它是一个局部变量。这就是为什么在分配它等于temp 之前你想delete[] arrayPointer,否则你永远无法回收arrayPointer 指向的内存。最后,当你说arrayPointer = temp; 时,内存中的temp 指向的内容没有被复制;只有temp 的(指针)值被复制到arrayPointer 中(因此您必须将原始数组的成员显式复制到新数组中,而不是相反)。然后,当您的进程退出该框架时,所有本地声明的变量都被释放,这就是为什么temp 作为指针消失,但它指向的内容没有被释放,因为它不在框架中(即使它被分配在框架)。

不过,有几个专业提示:我建议不要查看您的 for 循环,而是查看 std::copy,而 temp = nullptr; 实际上是多余的,因为为 temp(作为局部变量)分配的内存将一旦函数返回就被释放(如上所述)。

希望这在概念上有所帮助。但是,再说一遍:你绝对是对的 :)

【讨论】:

    【解决方案2】:

    如果p 的值是nullptr,那么delete p 什么也不做。

    如果您看到人们将原始指针设置为 null 然后将其删除的示例,那么这些示例就是错误的代码。

    设置指向nullptr 的指针对它之前指向的底层内存没有任何作用——这是 C++ 与大多数引用计数或垃圾收集语言之间的关键区别。

    另一方面,有许多“智能指针”类实现了引用计数语义; std::shared_ptr 是最著名的一个。因此,也许您已经看到有人使用其中之一。对于这些,通常将指针重置为 null 会减少其引用计数,如果引用计数为 1,则会导致它被删除。但这将由类处理;你不会自己打电话给delete。

    【讨论】:

      猜你喜欢
      • 2021-06-17
      • 2014-08-05
      • 1970-01-01
      • 1970-01-01
      • 2010-10-01
      • 1970-01-01
      • 2010-09-26
      • 2011-08-30
      • 2014-07-26
      相关资源
      最近更新 更多