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
中删除该元素不会影响副本。
我有一个 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
中删除该元素不会影响副本。