c++ - MSVC++ 2008/2010 调试配置中的 std::priority_queue 错误/问题

标签 c++ visual-c++

简单地说,我的问题有点像语言问题:以下问题是 MSVC++ 中的错误,还是“可接受的”行为?

在某人的代码中遇到严重的访问冲突后,我将问题的根源追踪到 std::priority_queue<> 的调试实现。在 MSVS 中。 (我已验证该问题在 2008 年和 2010 年均存在。)以下是说明该问题的简化示例代码:

#include <queue>
#include <iostream>

struct Less_than
{
    bool operator() (const int *x, const int *y) const
    {
        std::cout << "Less_than(" << *x << ", " << *y << ")" << std::endl;
        return *x < *y;
    }
};

int main()
{
    std::priority_queue<int *, std::vector<int *>, Less_than> q;
    int x = 0;
    int y = 1;
    q.push(&x);
    q.push(&y);
    std::cout << "Popping " << *q.top() << "..." << std::endl;
    q.pop();
}

输出应该是(并且在发布构建配置中):

Less_than(0, 1)
Popping 1...

但是,在调试构建配置中,输出是:

Less_than(0, 1)
Less_than(1, 0)
Popping 1...
Less_than(1, 0)

关键区别在于作为 pop() 的副作用发生的最终附加比较。在调试版本中,当从队列中弹出()顶部元素时,弹出()实现首先比较顶部元素与队列中的每个其他元素以验证它确实是最大元素.

这显然是一个问题(并且 有问题的代码中的问题),如果在上面的示例中,您正在使用指向对象的指针的 priority_queue 以及您自己的比较。 . 但我们也删除具有以下内容的对象:

delete pq.top();
pq.pop();

在这里,我们释放了 pq.top() 指向的对象,但是当我们尝试从队列中 pop() 指针时,pop() 的 Debug 实现首先尝试比较指向的现在无效的对象通过 top() 到队列中的所有其他内容!

当然,一个简单的解决方案是将上面的替换为:

T *p = pq.top();
pq.pop();
delete p;

但我的问题是:从技术上讲,原始代码不应该也能正常工作吗?更准确地说,我们是否应该能够依赖 pop() 不比较当前顶部元素与删除它的过程中的任何东西?我在这里读到的标准非常精确; C++03 的相关部分是 25.2.3.2.2 ( pop() ) 和 25.3.6.2 ( pop_heap() )。

提前致谢!

最佳答案

我会说你的代码 T *p = pq.top(); 是错误的。你得到一个 const& 到你队列中的一个项目。但是你删除了你得到的对象。所以基本上你使队列中的对象无效。
所以这是一件危险的事情。我会避免做这样的事情。

关于c++ - MSVC++ 2008/2010 调试配置中的 std::priority_queue 错误/问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6305978/

相关文章:

c++ - gcc 编译错误,在 Visual Studio 2008 C++ 中工作正常

visual-c++ - 如何将 GetProfileBinary 的结果保存到智能指针中?

C++:Visual Studio 2013 中奇怪的虚拟成员函数指针

c# - 使用Kinect [Algo]检测跳跃手势

c++ - 使用概念的部分特化

c++ - 带 -std=c++11 的 GCC 看不到 C++ 头文件(通过 PyDSTool)

c++ - 应用程序配置不正确错误 C++

c++ - std::vector 的奇怪行为

c++ - 两个一般六面体之间的碰撞检测

c++ - 如何找到编译瓶颈?