std::priority_queue::top返回一个常量值。但是,我想从优先级队列中删除top元素,并能够在其他地方修改它。
priority_queue<SomeClass, vector<SomeClass>, SomeClassCompare > pQueue;
...
SomeClass *toBeModified = &(pQueue.top());
pQueue.pop();
toBeModified->setMember(3); // I would like to do this
有没有办法可以从优先级队列中获取top元素(并从队列中删除)并按照我的意愿修改它?
答案 0 :(得分:14)
标准容器和容器适配器具有值语义。将元素推入队列时,会创建一个副本。从队列中删除对象时,该对象将被销毁。
即使top()
会返回对非const
的引用,只要从队列中删除该元素,该引用就会变为悬空,并且取消引用它将导致未定义的行为。< / p>
这就是说,std::priority_queue
会返回const
的引用,以防止您(有意或无意)使用其内部排序 - 这与关联容器的键的原因大致相同例如std::map
和std::set
是const
。
您可以执行的操作是构造top()
返回的值的副本,修改该副本,删除原始文件,然后将副本推送到队列中:< / p>
SomeClass obj = pQueue.top();
pQueue.pop();
obj.setMember(42);
pQueue.push(std::move(obj)); // You can move obj into the queue if you no more need it
另一方面,如果你需要引用语义,那么你必须将指针推入队列(可能是智能指针,具体取决于你的用例)和提供适当的自定义排序标准,根据它们指向的对象的属性对这些指针进行排序。
在这种情况下,请注意不要在运行时修改这些属性,以使它们的顺序不同。这将被视为“搞乱容器的内部排序”,并将导致未定义的行为。
答案 1 :(得分:1)
我不认为价值语义在这里起任何作用。所有其他容器具有相同的值语义,并且几乎所有容器都为front()
提供了可变引用。
priority_queue
禁止修改top()
元素有一个确切原因:这是因为特定元素位于顶部,因为根据其现值,它已经相应地符合条件。根据为队列配置的比较条件(运算符&lt;默认情况下),优先级队列中的元素始终排序。通过更改元素,您可能会破坏此条件,并导致使用已排序前置条件的所有操作都会导致未定义的行为。
简而言之,priority_queue
不允许修改包含元素的原因与set
和map
的键完全相同。
我知道您可能有一些专用的比较方法,您使用包含要比较的值的字段,并且您将修改该对象的任何内容,除了这个字段。这样您就不会违反排序顺序的要求。你可以做两件事:
将您的课程部分修改为mutable
。通过这种方式,您可以通过top()
获取元素并修改可变内容,即使这是const。
通过派生std::priority_queue
创建自己的优先级队列类。它有一个名为c
的字段(在 protected 部分中),其中包含对底层容器的引用 - 而底层容器总是有一个front()
方法来访问与top()
中的priority_queue
相同的元素。但是,为了您自己的安全,您应该创建关键字段const
,以便在构建期间设置它并且不会更改 - 只是为了将风险降至最低。