C++ 标准模板库优先级队列抛出异常并显示消息“无效堆”

Posted

技术标签:

【中文标题】C++ 标准模板库优先级队列抛出异常并显示消息“无效堆”【英文标题】:C++ standard template library priority queue throws exception with message "Invalid Heap" 【发布时间】:2009-01-23 22:15:43 【问题描述】:

使用 STL 的 priority_queue,我在尝试使用 pop() 时立即收到错误“无效堆”。我可以将我的值推送到队列中,队列的top() 是我所期望和可访问的。 pop(),去re-heap的时候,好像有问题。

我正在队列中存储指向模板类的指针。我有比较重载:

template <class type>
class vertexPriorityCompare

public:
   bool operator()(Vertex<type>* leftVertex, Vertex<type>* rightVertex) const
   
      if(leftVertex->getDistanceFromSource() < 0 && rightVertex->getDistanceFromSource() < 0)
      
         return false;
      
      else if(leftVertex->getDistanceFromSource() < 0)
      
         return true;
      
      else if(rightVertex->getDistanceFromSource() < 0)
      
         return false;
      
      else
      
         return leftVertex->getDistanceFromSource() > rightVertex->getDistanceFromSource();
      
   
;

priority_queue 是类的私有成员:

priority_queue< Vertex<type>*, vector< Vertex<type>* >, vertexPriorityCompare<type> > Q;

重载以它的方式工作,因为负距离被认为是无穷大,总是比其他任何东西都大;为了表示无穷大,距离被初始化为 -1。队列需要在顶部保持最小但非负数。

我取消引用重载中的指针,我在那里做的事情是允许的吗?还有,我需要重载另一个运算符吗?

我会附上代码,但如果我这样做,它似乎会吓跑人们。请求查看更多,我将附加到另一条消息。

我动态声明一个指向指针的指针数组,这些是被推送的,因为我假设priority_queue 通过引用存储,所以如果我只是将循环中声明的指针放入队列中,该指针就会超出范围.这些指针指向正确的Vertex&lt;type&gt;,并存在于整个函数中。

Visual Studio 2008 调试器将我带到“stdthrow.cpp”第 24 行。

【问题讨论】:

Visual Studio 调试器也应该给你一个调用栈。这也可能有帮助。 【参考方案1】:

这可能是您的比较功能。要进行测试,请将其替换为仅比较指针的简单版本:

bool operator()(...)

  return leftVertex<rightVertex;

如果问题不再出现,则问题是您的比较功能无效。您的比较器必须定义一个"strict-weak ordering"。我不够男人,无法证明它不是,但我敢打赌就是这样。

【讨论】:

+1 “严格弱排序”的一部分表示如果 Compare(x,y) 为真,Compare(y,x) 必须为假。如果两个距离值都是 -1,则此函数不会处理这种情况。 此外,指向 SGI 页面的链接指出了问题发生的哪里 - 在向量上使用的 *_heap 操作中以保持 priority_queue 的性质.在内部,make_heap、push_heap 和 pop_heap 被调用——因为没有维护严格的弱排序,它们会失败。 第一个 if 确保 -1,-1 双向返回 false 不? @Douglas Leeder:完全正确,这对于严格的弱排序来说是件坏事。 @Harper Shelby 在这方面似乎不行:对于这个比较,当两个距离都是-1时,比较(x,y)=比较(y,x)=假所以要求没有被打破.这种比较实现了以下“所有负距离都是等效的,并且严格低于任何非负距离”。没问题。【参考方案2】:

比较函数看起来不错,如果对象getDistanceFromSource() 的值没有改变,而该对象在队列中。这有保证吗?或者当对象在队列中或队列最初被填满时,是否对对象进行了更改,这会影响getDistanceFromSource()

【讨论】:

我之前不小心遇到了这个问题,这就是原因。【参考方案3】:

你从哪里调用这个函数?

我的猜测是无效堆是您从“此函数调用者的”代码传递给函数的指针。或者,当您将顶点从向量中取出时,您可能会越界。

我认为该功能没有任何问题。

请提供堆栈跟踪

【讨论】:

【参考方案4】:

这有点吓到我了:

我动态声明一个数组 指向指针的指针,这些是什么 被推,因为我假设 priority_queue 通过引用存储,所以 如果我只是把一个指针声明在 循环进入队列,那个指针 超出范围。这些指针 指向正确的顶点,并且存在 贯穿整个函数。

目前尚不清楚您是如何填充队列的。 您必须创建 Vertex 对象,并且它们必须保留在内存中,并且在它们在队列中的整个时间内返回相同的距离。

队列不按引用存储,它存储副本 - 但在这种情况下,您放入的是指针,因此它复制指针,该指针仍将指向您分配的原始对象。

我认为我们需要一个简短的完整示例才能进一步了解。

【讨论】:

【参考方案5】:

如果没有调用堆栈,确定问题所在会有点困难,但是您要么没有正确分配Vertex&lt;...&gt;,试图从堆栈中释放Vertex&lt;...&gt;,要么没有将Vertex&lt;...&gt;* 初始化为有效值。

【讨论】:

以上是关于C++ 标准模板库优先级队列抛出异常并显示消息“无效堆”的主要内容,如果未能解决你的问题,请参考以下文章

C++标准库异常类

C++ 标准模板库STL 队列 queue 使用方法与应用介绍

C++标准模板库(STL)——queue常见用法详解

C++学习(三一八)Android的Logcat

C++ exception类:C++标准异常的基类

避免 unix 中的标准库冲突