C++ list/queue 最高 return 值

C++ list/queue top return value

我有一个 C++ 代码如下:

#include <iostream>
#include <queue>
#include <list>
using namespace std;

int main(){
    priority_queue<pair<int, int>> q;
    q.push({8, 8});
    q.push({19, 19});
    q.push({23, 23});

    while (q.size() > 0){
        auto& cur = q.top();
        q.pop();
        cout << cur.first << " " << cur.second << " "; // returns 19 19 8 8 8 8
    }
    cout << endl;

    list<pair<int, int>> newq;
    newq.push_back({19, 19});
    newq.push_back({8, 8});
    newq.push_back({23, 23});
    while (newq.size() > 0){
        auto& cur = newq.front();
        newq.pop_front();
        cout << cur.first << " " << cur.second << " "; // returns 19 19 8 8 23 23
    }
    cout << endl;
    return 0;
}

使用 auto&auto 迭代 list 产生相同的输出。但我试图理解为什么如果我在遍历优先级队列时使用 auto&,输出是错误的。如果我将其更改为 auto 我的输出是正确的:

    priority_queue<pair<int, int>> q;
    q.push({8, 8});
    q.push({19, 19});
    q.push({23, 23});

    while (q.size() > 0){
        auto cur = q.top();
        q.pop();
        cout << cur.first << " " << cur.second << " "; // returns 23 23 19 19 8 8
    }
    cout << endl;

感谢您的澄清!

    auto& cur = q.top();
    q.pop();

这里 auto & 不起作用而 auto 起作用的原因是,使用 auto & 您可以在队列的 top() 处获得对对象的引用...

... 立即,在下一行,队列顶部的那个对象被删除并销毁,留下一个悬空的引用。

从那时起使用该引用会导致未定义的行为。

使用auto代替,复制对象,并且在原始对象被销毁后副本继续存在。

当与 std::list 一起使用时,类似的错误当然有可能不会产生明显的错误结果,但它仍然是未定义的行为。 “未定义行为”的意思就是:任何事情都有可能发生。包括得到预期的结果,纯属偶然。一个好的静态分析工具,比如 valgrind,应该能够捕获这个错误。

当你这样做时:

auto& cur = q.top();

您正在引用 priority_queue 中的顶部元素。但是当你这样做时:

q.pop();

此元素已删除,所有对它的引用(包括 cur)都保留为悬空状态。任何从 cur 读取的尝试,例如:

cout << cur.first << " " << cur.second << " ";

将调用未定义的行为,它可以做任何事情,包括给出您观察到的结果。


正在做:

auto cur = q.top();

很好,因为您正在制作顶部元素的副本。从 q 中删除该元素不会影响副本。