【问题标题】:C++ Avoiding Deleting Memory TwiceC++ 避免两次删除内存
【发布时间】:2013-02-20 17:22:57
【问题描述】:

我在使用 C++ 中的内置指针时遇到了问题。当我的程序终止时,我的类析构函数都会被调用。我有一个数据类、一个队列类和另一个包含使用队列的数据类,如下所示(注意即时粗略编码):

class Data {
  int x;
}

class Queue {
  class Node {
    Data* x;
  }
  Node* head;
}

class C1 {
  Queue q;
}

class C1Queue{
  class Node {
    C1* c;
  }
  Node* head;
}

我还有另一个队列 q2,它不驻留在对象中。我从一个文件中加载了两个队列,所以我说的是(假设 cQueue 是一个 C1Queue):

Data *d = new Data(0);
q2->pushBack(d);
C1 c = new C1();
cQueue->pushBack(c->pushBack(d));

如您所见,我有一个队列 (q2) 保存指向每个数据的指针,以及一个带有队列的对象,该队列保存指向与 q2 所保存的相同数据的指针。 现在,当我的程序终止时,我希望释放所有数据。但是,当对象被释放时,要么首先释放 q2,当要释放 C1 对象时,它们释放队列,然后删除与刚刚删除的 q2 相同的数据。或者另一种情况是先释放对象(我不确定发生哪种排序),然后释放 q2 并运行到已删除的内存中。

所以问题是内存空间被删除了两次,不好。一旦内存被删除,它就会被释放给其他程序使用,因此再次删除该内存空间会导致段错误。

也许我在这里遗漏了一些东西,但是如果没有特殊类型的指针(我不能使用特殊类型的指针),我无法弄清楚如何做到这一点。

我能想到的唯一方法是阻止 C1 对象释放它的队列,但释放它本身的其余部分,但我不知道该怎么做。如果有人可以帮助我,我将不胜感激。

【问题讨论】:

  • 请注意,在空指针上使用delete 是一种安全操作(大多数情况下它什么都不做)。这就是为什么强烈建议将空指针设置为NULL,或者更好的是,在deleted 之后设置nullptr
  • 这是真的,但是删除已经释放的内存空间会导致大多数编译器出现分段错误(因为内存已经分配给管理它的任何东西)
  • 哦,天哪,等一下 shared_ptr 家伙进来吧。至于你的问题,通常最好按照创建对象的相反顺序销毁对象。这应该是可能的,除了多线程代码。您还需要决定谁拥有这些对象以及谁只使用它们
  • 语言保证在空指针上调用 delete 是安全的。但是,对非空指针多次调用 delete 是安全的。 (称为“双重免费”)
  • 如果可能,通常最简单的方法是复制数据,而不是让多个指针指向同一数据。如果你不能这样做,几乎你自己合理的替代方法是使用(并编写,如果你不能避免它)一个引用计数类,这样你只有在对它的所有引用都消失时才删除数据。在这里将指针设置为 NULL 将无济于事,除非您构建一个跟踪给定对象的所有指针的指针,并且在删除任何对象时将 all 指向对象的指针设为 NULL。跨度>

标签: c++ memory-leaks destructor memory-management


【解决方案1】:

由于您(显然)无法使用 std::shared_ptr 之类的细节,您可以尝试以下三种补救措施之一:

  • 手动重新计数。强制每次将Data 推入队列时,其引用计数会增加,并在清理Queue 时减少引用计数。当引用计数为零时,delete this(但请确保始终在堆上分配 Datas!)
  • 指定一个对象来“拥有”Data 元素。只有该对象可以销毁Data(您甚至可以使用私有析构函数和友元类强制执行此操作)。您可能需要不止一种。 (如果你引用这个代理,这将成为一个穷人的std::shared_ptr)。
  • 使您的Datas 可复制,并使用全新的对象进行所有操作。这适用于不需要保持同步的少量数据(例如,包含两个整数的 Point2D 类)。

【讨论】:

  • 非常感谢!引用计数策略对我有用。顺便说一句,绕过强制在堆上分配的一种方法是制作一个标志来指定它是否是动态分配的,如果标志条件成立,则删除该对象。无论如何,这让我头疼不已,再次感谢!
猜你喜欢
  • 2012-11-30
  • 1970-01-01
  • 1970-01-01
  • 2014-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-19
  • 2021-04-24
相关资源
最近更新 更多