【问题标题】:Right way to remove an element in std::set<Node *>在 std::set<Node *> 中删除元素的正确方法
【发布时间】:2019-03-26 20:41:02
【问题描述】:

我有一个图表类

struct Graph
{
  list<Node *> vertices;
};


int main()
{
  Graph g;
  // fill out graph

  return 0;
}

我想执行一个 Dijkstra-shortest-path-like 算法。第 1 步是从所有节点中创建一个集合,我通过

完成
set<Node *> outstanding;
for (auto itx=g.vertices.begin(); itx!=g.vertices.end(); itx++)
{
  outstanding.insert(*itx);
}

第 2 步是提取具有特定属性的顶点

  double max_height_comp = (*(g.vertices.begin()))->max_height;
  set<Node *>::const_iterator it_max;
  while (!outstanding.empty())
  {
    for (auto its=outstanding.begin(); its!=outstanding.end(); its++)
    {
      if ((*its)->max_height >= max_height_comp)
      {
        max_height_comp = (*its)->max_height;
        it_max = its;
      }
    } 
 outstanding.erase(it_max);

我收到这些运行时错误

malloc: *** error for object 0x7fc485c02de0: pointer being freed was not allocated 
malloc: *** set a breakpoint in malloc_error_break to debug

我担心erase()outstanding 的元素上调用free()delete,它们是指针。但它为什么要这样做呢?我只想从集合中删除指针的值,不想删除指针指向的数据。

【问题讨论】:

  • 我怀疑您将迭代器擦除到同一个节点两次。你能在擦除之间显示你初始化it_maxmax_height_comp的代码吗?
  • @PeterBell 感谢您的评论。我编辑了帖子。
  • 所以让我们分解一下。您的循环所做的只是擦除集合中大于或等于(*(g.vertices.begin()))-&gt;max_height;? 的最大项目。那是对的吗?如果是这样,这不需要for 循环。可以使用std::max_element 获得最大项目,并与max_height 进行比较。如果是这样,请删除该迭代器。

标签: c++ pointers malloc stdset


【解决方案1】:

根据您显示的代码,我认为您没有在循环迭代之间重置 it_maxmax_height_comp。因此在第二次循环行程中,所有内容都小于max_height_comp 并且it_max 永远不会更新。

使用&lt;algorithm&gt;中的函数可以完全避免这个问题,这样变量就可以通过构造保持在正确的范围内。

while (!outstanding.empty())
{
    auto it_max = std::max_element(outstanding.begin(), outstanding.end(),
        [](Node * left, Node * right)
        {
            return left->max_height < right->max_height;
        });

    Node * node_max = *it_max;
    outstanding.erase(it_max);

    // Use the node
}

【讨论】:

  • outstandingstd::set... 有更好的方法来获取最大元素
  • 怎么样——it_max = std::prev(outstanding.end());?
  • @PaulMcKenzie 这不起作用,因为该集合是按地址而不是按高度排序的。此外,如果不丢失彼此具有相同高度的元素,则无法按高度对集合进行排序。
【解决方案2】:

您似乎没有为每次迭代更新max_height_comp。第一次通过while 循环后,它将保持上一次迭代的最大值,因此it_max 不会被更新,您将尝试第二次擦除该节点。您需要在每个循环开始时重置max_height_comp,使用包含在outstanding 中的数据或小于任何可能值的数字。

max_height_comp 的初始值也有可能大于 outstanding 中的任何值,这将导致尝试擦除默认构造的迭代器。

【讨论】:

    【解决方案3】:

    来自文档here

    std::set::erase

    从集合容器中删除单个元素或一系列元素([first,last))。

    这通过移除的元素数量有效地减小了容器的大小,这些元素被销毁了。

    您的指针似乎由于某种原因没有得到更新,当调用 erase() 时,它正试图销毁未分配的内容。

    【讨论】:

      猜你喜欢
      • 2011-02-21
      • 2014-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-09
      • 2011-05-15
      • 1970-01-01
      相关资源
      最近更新 更多