【问题标题】:Deleteing lists in C++ causes crash [duplicate]在 C++ 中删除列表会导致崩溃 [重复]
【发布时间】:2015-01-23 09:47:57
【问题描述】:

删除列表内容的正确方法是什么。目前我正在这样做。

std::list<CSchSuggestBar*>::const_iterator iter = m_pRescheduleReasons.begin();
for (; iter != m_pRescheduleReasons.end(); ++iter)
{
    delete *iter;
}

但是删除 *iter 似乎会导致崩溃。

如果我只是打电话给m_pRescheduleReasons.clear()是首选

编辑:

指针如何存储在列表中的方式如下:(我做了一个单独的项目来隔离问题:当第一次出现崩溃时调用删除..但是有一个有效的对象,其中指针也指向了?所以我不太清楚它为什么会崩溃?

std::vector<Foo*> f;
for(int i = 0; i < 10; i++)
{
  f.push_back(f1);
}
 std::vector<Foo*>::const_iterator it = f.begin();
for (; it != f.end(); ++it)
{
   delete *it; 
}

编辑:我代表我解决了这是一个愚蠢的错误

【问题讨论】:

  • 列表中的指针实际指向什么?如何将项目添加到列表中? 什么你添加到列表中?
  • 我从谷歌搜索“在 C++ 中删除列表”中发现了很多好的建议
  • 还要注意clear 函数只会使列表为空,它不会删除列表中的指针,因此如果您确实分配了这些指针,那么您将有内存泄漏。但是,您应该在删除列表中的所有指针后清除列表。
  • 您是否有充分的理由不使用std::list&lt;CSchSuggestBar&gt;?如果是这样,可能值得在问题中提及。
  • 我认为您的问题与std::list 无关(查看my answer 中的简单工作示例),因此切换到std::vector 时会遇到同样的问题。这就是我投反对票的原因,我希望你能解决这个问题。

标签: c++ list crash


【解决方案1】:

使用

std::list<std::unique_ptr<SomeType>> mylist;

何时会自动删除带有list::clear()list::~list() 的内容。由于unique_ptr不能被复制,你必须移动它们

mylist.push_back(std::move(std::unique_ptr<SomeType>(new SomeType(args))));
mylist.push_back(std::move(make_unique(new SomeType(args))); // C++14

你也可以使用list::emplace

mylist.emplace_back(new SomeType(args));

但是如果节点分配失败,new SomeType(args)分配的内存将不会分配给unique_ptr,因此会泄漏。

【讨论】:

  • +1 建议unique_ptr。 -1 建议 emplace_back 用于包含 unique_ptr 的容器。如果链表节点分配失败,指针很可能会泄露。
  • std::unique_ptr大多数情况中是正确的选择。但我认为这并不能解决实际问题。如果提问者应用这个建议,问题可能会变得更大。这种考虑让我投了反对票。
  • @SebastianRedl 好点。我已经编辑了我的答案。
  • @Wolf 我回答了(原始)问题,即使我的建议可能无法解决实际问题(问题没有解决问题),但为什么问题会变得更大?您的反对意见表明使用 unique_ptr 没有帮助,我对此表示反对。
  • 你是对的,问题是低质量的(也在我的编辑之后)。切换到unique_ptr 的建议确实是一个很好的建议。为什么它变得更糟是崩溃的原因会被隐藏。例如,关闭范围可能会导致它,这很难调试。我认为提问者只有基本的 C++ 技能。
【解决方案2】:

老东西,我想你想要 Qt 中的 deleteAll 宏之类的东西。

   bool deleteCSchSuggestBar(CSchSuggestBar *item)
   {
      delete item;
      return true;
   }

   m_pRescheduleReasons.remove_if(deleteCSchSuggestBar);
   m_pRescheduleReasons.clear();

【讨论】:

  • 您可以在 remove_if 中使用 lambda。
  • 当然可以,但我通常针对的是旧版本的 c++,而不是 C++11。
  • 为什么要限制使用旧的 C++?几岁? 1998 年?准标准?
【解决方案3】:

你发布的代码

std::list<CSchSuggestBar*>::const_iterator iter = m_pRescheduleReasons.begin();
for (; iter != m_pRescheduleReasons.end(); ++iter)
{
    delete *iter;
}

工作正常。我用它做了一个working example

崩溃可能是由析构函数调用本身引起的。

或者,在您的情况下更有可能:您在 悬空指针(已被销毁的前一个对象的地址)上调用 delete。销毁循环中的所有对象后尝试添加此行:

m_pRescheduleReasons.clear();

这会导致一个空列表。

【讨论】:

  • 我已经更新了我的答案。
【解决方案4】:

如果我只调用 m_pRescheduleReasons.clear() 是否首选

这真的归结为用例......

如果您使用删除迭代器;调用,只有迭代器会失效....但是如果你也想删除指针,那么 ,delete *iter 应该这样做。

考虑一下:

如果您拥有该列表中的对象,那么删除这些对象将是一个有效的用例。

但是说在诸如主题观察者模式之类的用例场景中,您需要维护一个观察者列表,随机删除观察者并不是一个好的设计选择。

【讨论】:

  • 提问者表示delete *iter seems to cause a crash我认为确实是这样,但是帖子中没有包含“恶意”析构函数本身。顺便说一句:提问者不使用delete iter,我认为这个答案到目前为止没有帮助(-1)
  • 这个回答是对这个问题如果我只调用 m_pRescheduleReasons.clear() 是首选吗?我不明白这怎么值得一票否决....用例是合法的,不是吗?
猜你喜欢
  • 2015-10-22
  • 2021-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多