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<type>
,并存在于整个函数中。
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<...>
,试图从堆栈中释放Vertex<...>
,要么没有将Vertex<...>*
初始化为有效值。
【讨论】:
以上是关于C++ 标准模板库优先级队列抛出异常并显示消息“无效堆”的主要内容,如果未能解决你的问题,请参考以下文章