【问题标题】:Delete dynamically allocated memory after swapping its pointer交换指针后删除动态分配的内存
【发布时间】:2021-08-24 00:25:39
【问题描述】:

我对 C++ 比较陌生,我想同时了解内存管理和指针。

假设我有下面的代码

int* p1;
int* p2;
int* p3 = new int[some size];

p1 = p3;

std::swap(p1,p2);

如何正确删除动态分配的内存?做delete[] p3 够吗?之后我也应该删除p2吗?

【问题讨论】:

  • Is doing delete[] p3 enough? 是的。 Should I delete p2 too after that?没有。
  • 我主张在 2021 年为任何新的 C++ 开发人员从一开始就使用 C++ 智能指针,除非出于教学目的要求。
  • std::swap(p1,p2); 之前确保您执行p2 = nullptr;,否则交换将执行未定义的行为。
  • 这样想:分配的内存是一辆汽车,一些指向该内存的指针就像打开同一辆车的几把钥匙。一旦你摧毁了汽车(通过使用钥匙设置炸弹),其余的钥匙就没有用了;最糟糕的是:它们指向一个被破坏的物体,所以不要试图再次爆炸它。
  • 通过哪个指针删除动态分配的内存并不重要,您可以使用p2p3 中的一个 - 但不能同时使用两者。一旦内存被删除,all 指向的指针就会失效。在新分配之前仍在阅读是未定义的行为。无论如何你都有UB,因为你在传递给std::swap时正在读取未初始化的p2指针。为避免,请为其分配一个值,例如。 G。 nullptr.

标签: c++ pointers memory-management


【解决方案1】:

当你做这样的事情时,口语会有些模糊:

delete x;

我们说“我们删除x”。严格来说是错误的,因为删除的是x指向的对象。

通过new/new[] 分配的每个对象都必须通过调用delete/delete[] 来销毁。无论您有两个或多个指向同一个对象的指针都不会改变这一点。

int* p1 = nullptr;
int* p2 = nullptr;
int* p3 = new int[some size];      // p3 points to the array

p1 = p3;                           // p1 points to the same array

std::swap(p1,p2);                  // now p1 == nullptr, p2 points to the array

请注意,您的示例中的指针未初始化。读取它们的值会导致未定义的行为。因为这不是问题的症结所在,所以我通过初始化它们来避免这个问题。

通过new [] 创建了一个数组,您必须通过delete [] 删除该数组。你不能删除它两次。所以要么打电话给delete[] p3;delete[] p2;,但不能同时打电话。

PS: 评论已经提到了智能指针,我也建议你阅读它们。现在你不应该使用原始的拥有指针。拥有指针是您需要调用delete 的指针,它“拥有”指向的对象。原始指针只能用于“观察”,即您永远不必担心在原始指针上调用delete(或delete[])。当然,您仍然需要注意指向的对象是否仍然存在,但这并不特定于动态分配:

 int* p;
 { 
     int x = 42;
     p = &x;         // p points to x;
 }                   // x goes out of scope
 // here p is not a valid pointer anymore

【讨论】:

  • 我会接受这个答案,因为它总结了 cmets 所说的一切
【解决方案2】:

要了解这里发生了什么,添加一些调试语句会有所帮助,即:

std::cout << p1 << " " << p2 << " " << p3 << "\n";

跟踪将产生如下输出:

0 0 0x15e7eb0
0x15e7eb0 0 0x15e7eb0
0 0x15e7eb0 0x15e7eb0

(注意我将p1和p1初始化为nullptr

p3 最初指向一些内存。在分配p1 = p3 之后,p1 现在指向与 p3 相同的内存地址。当您交换指针时,现在是 p2 指向与 p3 相同的内存地址。

这里有几点需要注意:

  • 必须delete[] 与对应的new[] 配对(不要将deletenew[] 等联系起来)
  • 对已删除的对象调用 delete 是未定义的行为
  • 在空指针上调用 delete 是非常安全的

如您所见,处理原始指针和内存分配很容易导致陷阱。通常建议使用智能指针,或者如果您有非拥有指针,则使用observer_ptr 之类的抽象来清楚地指示代码中指针的用途。

【讨论】:

  • 泰。希望我能同时接受 2 个答案。你给了我更深的理解,我相信,并提供了一种自己测试这些东西的方法
猜你喜欢
  • 2019-09-17
  • 2019-07-12
  • 2015-02-05
  • 2012-11-06
  • 1970-01-01
  • 2011-06-17
  • 1970-01-01
  • 1970-01-01
  • 2013-12-27
相关资源
最近更新 更多