- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我制作了一个简单的霍夫曼编码程序来输出字符的单独编码并保存编码文件。这是一个作业,有人告诉我使用 const_cast
在 heap.top()
如果我们 heap.pop()
被认为是未定义的行为之后,但我不确定我明白为什么。
我已阅读 cppreference关于 std::pop_heap
这是我们调用 heap.pop()
时调用的底层函数我相信一个 nullptr
在比较中仍然是定义和理解的。当我调试它时,它似乎并没有异常运行。
这是一个例子
#include <functional>
#include <queue>
#include <vector>
#include <iostream>
#include <memory>
template<typename T> void print_queue_constcast(T& q) {
while(!q.empty()) {
auto temp = std::move(const_cast<int&>(q.top()));
std::cout << temp << " ";
q.pop();
}
std::cout << '\n';
}
template<typename T> void print_queue(T& q) {
while(!q.empty()) {
std::cout << q.top() << " ";
q.pop();
}
std::cout << '\n';
}
int main() {
std::priority_queue<int> q1;
std::priority_queue<int> q2;
for(int n : {1,8,5,6,3,4,0,9,7,2}){
q1.push(n);
q2.push(n);
}
print_queue(q1);
print_queue_constcast(q2);
}
谁能解释背景中实际发生的事情是未定义的行为,或者在某些情况下会导致此失败?
最佳答案
tl;博士:也许;也许不吧。
语言级安全
与集合一样,priority_queue 负责对其元素进行排序。对元素的任何修改都可能会“破坏”排序,因此唯一安全的方法是通过容器自己的变异方法。 (事实上,没有人真正提供这样的东西。)直接修改元素是危险的。为了加强这一点,这些容器只暴露 const
访问您的元素。
现在,在语言层面,对象实际上不会有 const T
的静态类型;很可能他们只是 T
s .因此,修改它们(在 const_cast
之后以欺骗类型系统)在这个意义上没有未定义的行为。
图书馆级安全
然而,您可能会破坏使用容器的条件 . priority_queue 的规则实际上并没有这么说,但是因为它的变异操作是根据像 push_heap
这样的函数定义的。和 pop_heap
,如果容器的排序在您直接更改后不再满足,则您使用此类操作将破坏这些函数的先决条件。
因此,如果您破坏排序并随后以依赖于完整排序的方式改变 priority_queue,您的程序将具有未定义的行为。如果你不这样做,从技术上讲,你的程序的行为是明确定义的;然而,一般来说,你仍然是在玩火。 一个 const_cast
应该是不得已而为之的措施。
那么,我们站在哪里?
问题是:你打破了顺序吗?从元素移出后元素的状态是什么,是否通过在队列顶部放置处于该状态的对象来满足排序?
shared_ptr
s,我们从文档中得知,一个来自 shared_ptr
安全地变成空指针。priority_queue
排序由 std::less
定义, 对原始指针产生严格的全序; std::less
在 shared_ptr
实际上会调用它的基本情况 operator<
,但是 that in turn is defined to invoke std::less
on its raw pointer equivalent .std::less
's pointer ordering is strict and total, where null pointers land in this ordering is unspecified .pop()
是否将有未定义的行为 .int
的 MCVE 示例是安全的,因为
std::move
上的
int
没有任何工作要做:它只会复制
int
。因此,排序不受影响。)
pop()
不会返回弹出的东西,然后你可以
move
从。集合和映射的类似限制是我们现在拥有
node splicing features 的原因。对于那些容器。对于priority_queue 没有这样的事情,它只是一个像 vector 这样的另一个容器的包装器。如果您需要更细粒度的控制,您可以将其替换为您自己的具有您需要的功能的控制。
shared_ptr
增量(如在您的原始代码中),我可能只需要复制 ,除非您有一些非常极端的性能要求。这样,您就知道一切都将得到明确定义。
int
复制(如在您的 MCVE 中),一个
std::move
完全没有意义(没有可以窃取的间接资源!)而且无论如何你都在做一个拷贝,所以重点是没有意义的,你所做的只是无缘无故地创建更复杂的代码。
关于c++ - 为什么 const_casting a heap.top() of priority_queue 有未定义的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65267072/
我尝试使用 constructor 为 priority_queue 分配内存,但出现以下错误: No matching constructor for initialization of 'prio
#include #include #include #include struct Temp { int p; std::string str; }; struct Te
这个问题在这里已经有了答案: Boost heap Setting user defined compare function (1 个回答) 关闭 8 年前。 我正在尝试为自定义 Edge 类设置
我是 C++ 的初学者。我正在尝试使用 std::priority_queue 创建最大堆和最小堆。只创建一个 maxheap 可以正常工作,但不能同时创建两者。我似乎无法理解错误。我收到以下错误:无
如何清除使用用户定义比较的priority_queue? 来自 std::priority_queue documentation ,我将 priority_queue 的使用减少到我需要的情况(=
如何清除使用用户定义比较的priority_queue? 来自 std::priority_queue documentation ,我将 priority_queue 的使用减少到我需要的情况(=
我有一个类Node除了存储数据外,它还有一个指向其父节点的指针 Node .我将一些节点存储在 priority_queue 中并覆盖 queue; 问题是,父指针似乎搞砸了。我的猜测是,当我弹出
我想创建一个名为 Edge 的对象,它从其构造函数将自身插入到 priority_queue 中。也就是; Class Edge { int m_from; int m_to; in
代码如下: 比较算法 class PathComp{ public: virtual bool betterThan(const PathInfo& path1, const PathInfo& pa
我有 priority_queue。我的函数 delete 在内存消耗和时间方面不是很合理。我见过类似的主题,但它们对我没有帮助。 How to remove element not at top f
我有这样的代码 priority_queue, decltype(&VD::CompareByDistance)> pqDistances(&VD::CompareByDistance); 在哪里 c
我正在研究最小堆的解决方案,除了自定义比较器之外,它还需要支持删除任何元素。完全自定义的堆实现是一种方法。但我想依靠 C++ STL 来进行所需的操作。 C++ 文档和 StackOverflow 答
我有一个 Dijkstra使用 priority_queue 的类具有自定义比较功能。我将队列命名为 DijkstraPriorityQueue用using陈述。在类构造函数中,我初始化了队列。为此,
我正在为这个问题编写代码。当我遇到问题时,整数流的中位数。请注意,此问题不是算法问题,而是 priority_queue 大小的模糊行为。 #include using namespace std;
int main() { list letters; priority_queue, less>letters_trans; cout input(cin), input_e
我的文件顶部有这些: #include typedef struct cell_s { unsigned int x; unsigned int y; unsigned in
你好,我需要创建一个类,其中包含一个 priority_queue 字段,其比较函数需要访问类中的另一个字段。简而言之,我需要写这样的东西: class A { B foo; prio
当我尝试使用 priority_queue 作为类成员时,我卡住了。请查看下面的代码,让我知道为什么 L1 看不到 Type 但 L2 可以看到。我尝试了 struct,也尝试了 ctor。 如果这是
我有一个服务器应用程序,它接受传入的查询并执行它们。如果查询太多,则应将它们排队,如果执行了其他一些查询,则也应执行排队的查询。由于我想传递具有不同优先级的查询,我认为使用 priority_queu
考虑一个 std::priority_queue,其中 N 元素具有相同的优先级。现在考虑具有任意优先级的元素的一些 pop() 和 push(),因此生成的队列由所有这些 N 元素组成上面提到的加上
我是一名优秀的程序员,十分优秀!