关于C 的动态内存分配

Regarding dynamic memory allocation in C++

本文关键字:内存 分配 动态 关于      更新时间:2023-10-16

假设我通过p1的动态内存分配如下,

int* p1 = new int;
*p1 = 1;

我知道p1引用的内存可以通过

释放
delete p1;
p1 = nullptr;

但是我想知道是否还有另一个指向1的指针p2,我可以delete这个指针以释放内存吗?Pointer p1会发生什么?另外,p1p2之间的关系实际上是什么?例如,

int* p1 = new int;
*p1 = 1;
int* p2 = p1;
// Can I delete p2 like this? And what would happen to p1?
delete p2;
p2 = nullptr;

您可以删除p2,但是删除p1将导致不确定的行为和可能的分割故障。

它是这样的工作:

  1. 在某个地址分配内存。
  2. p1p2指向此内存位置。
  3. 一旦删除了p2 -p1仍指向此内存位置。没有泄漏,一切都还好 - 只是不要退出p1。您可以自由执行p1 = nullptr,但不能*p1 = 1。另外,您无法删除p1,因为它已经被删除,并且您可能会捕获Segfault。

您在(旧)C 中描述一个非常清楚的问题:当几个指针指向相同的动态内存时,它删除了它?p>如果您同时删除p1p2,则删除具有不确定行为的内存(在最好的情况下是崩溃),如果您删除p1p2,并且您继续使用其他指针使用内存 - 您正在使用 - 您正在使用悬空指针,这是不确定的行为(在最好的情况下,崩溃)。您需要确保删除一个指针时 - 您不要在其他指针中使用该内存。

c 11引入了解决此问题的标准方法:使用自我计数指针,只有最后一个指针删除内存:

auto p1 = std::make_shared<int>(0);
auto p2 = p1;

现在,最后一个指针Alive将删除分配的内存,您不必担心删除什么的人。

以及指针P1会发生什么?另外,P1和P2之间的关系实际上是什么?

他们的基本关系是他们指向分配后int* p2 = p1;后从动态内存分配获得的相同地址。

因此,删除它们中的任何一个都可以释放分配的内存。将其中一个设置为nullptr不会影响另一个。

因此,您剩下的悬挂指针无法安全删除。

您可以删除p1p2。没有区别。但是你不应该删除两者。另外,一旦删除了一个,就不应使用另一个。程序员对此负责。该语言本身不会提供任何帮助。这里有很多不同的方法来编写不良代码。

有几种处理此操作的技术/模式。经常将智能指针用于此。查看std :: shared_ptr文档。请勿使用过时的auto_ptr

我最喜欢的模式是"所有权"。这意味着一个指针"拥有"分配,而所有其他指针都只使用。这需要在编程时进行某些纪律,但是一旦应用了这项工作,结果代码就清晰又简单。例如:

class MyClass
{
public:  ~MyClass() { for(char *p: myStringsDict) delete p; }
private:
    std::unordered_set<char*> myStringsDict;
};

看这堂课很明显(尽管添加适当的评论很高兴)它拥有字符串字典,只要存在此类的实例,这些字符串就有效。这些指针可以用于该类拥有的结构中,它们可以作为参数传递给函数等。很明显,何时不再使用它们。

在服务器编程中,当多个线程运行时,双重删除可能非常危险且难以跟踪。因为删除第一个指针后,内存变得自由,并且可以在其他线程上分配其他目的。当第二个指针被释放时,可能会删除有效的分配,而其他代码对此一无所知,并且正在继续使用此内存。

解决所有这些问题的很好的解决方案是垃圾收集。当使用明确分配时,程序员需要以这种方式应用额外的精力。

让我们探索房地产类比,在这里记忆扮演土地和指针的作用并不是很难以充当地址。

指针变量是一个黄色的邮政注释。您可以在上面写一个街道地址。从免费商店分配的变量是某个地址的一块土地。

 int *p = new int;

您要求城市在某个地方找到一块未使用的土地,并将标题分配给您自己。您将其街道地址写在黄色音符上。

 *p = 1;

您在该地址建造一个整洁的小房子。

  int *q = p;

您制作黄色音符的副本。你忘记了一段时间。

 delete p;

您拆除了建筑物,放弃了对土地的权利。这座城市可以将其分配给其他人。也许有人想在那里建造另一个小建筑物,或者铺设铁路轨道或建立鲨鱼池。请注意,这对您的任何黄色音符都没有任何作用。

p = nullptr;

您擦拭黄色音符。您的其他黄色音符徘徊。

*q = 2;

您找到了另一个黄色的音符,请阅读一个曲折地址,并假设土地是您的。不好的举动。您继续在别人的土地上建造一个整洁的小房子。新主人不在乎(他们无法了解)。明天,他们可能会拆除您的建筑物,并将自己的建筑物置于适当的位置,或者用火车淹没您,或者在您身上倾倒100000吨水和3个Makos。那真是不愉快!不要触摸什么不是您的。

使用新的delete分配动态存储器时,只要您使用新的免费创建P1,则应通过delete释放它它使用删除。您将p2声明为指向相同内存的指针,如果要在 p1上免费呼叫删除p2,则可以将P1指向P1点,但是可以通过在p1或p2上调用delete来释放内存。

。 。

如果您在p1上调用删除

delete p1;
*p2 = 1;

将导致不确定的行为。