在 c++ 中应按什么顺序释放内存?

In what order should memory be deallocated in c++?

本文关键字:顺序 释放 内存 什么 c++      更新时间:2023-10-16

我在理解在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是一个指针,而不是数组本身。这是一个非常关键但经常被误解的观点。就我个人而言,我为此挣扎了很多。因此,当您简单地说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作为指针消失,但它指向的内容没有被释放,因为它不在帧中(即使它是在帧中分配的)。

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

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

如果p有值nullptr,则delete p什么都不做。

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

设置指向nullptr的指针不会对它之前指向的基础内存执行任何操作 - 这是C++与大多数引用计数或垃圾回收语言之间的关键区别。

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