我可以通过清除其底层容器来清除priority_queue吗?

时间:2016-01-21 05:56:35

标签: c++ c++11

以下代码继承std :: priority_queue并提供调用内部clear()的{​​{1}}

std::vector
clear()

当我用g ++,MSVC ++和clang测试它时,它会产生预期的输出:

#include<iostream>
#include<queue>
using namespace std;
template<class type>
struct mypq :public priority_queue<type> {
    void clear(){
        this->c.clear();
    }
};
mypq<int>pq;
int main() {
    for(int i=0;i<10;++i)
        pq.push(i);
    pq.clear();
    for(int j=-5;j<0;++j)
        pq.push(j);
    while (!pq.empty()){
        cerr<<pq.top()<<endl;
        pq.pop();
    }
}

但是我没有看到任何保证,即当priority_queue不为空时,清除内部向量将与调用-1 -2 -3 -4 -5 相同。虽然我知道其他方法来清除它,比如交换或使用空的priority_queue分配它,但我认为如果这个代码能够很好地工作,那么它会更有效,因为向量中分配的内存是可重用的。所以我想知道这段代码是否可移植或不会一直有效?

2 个答案:

答案 0 :(得分:4)

  

但是我没有看到任何保证,即当priority_queue不为空时清除内部向量与调用pop()相同。

因为那不是一回事。 std::priority_queue是一个专门设计的容器适配器,可以通过严格的弱排序来保存订单。如果您没有指定队列将具有的容器类型(在示例中没有),则默认类型为std::vector

因此,在非空优先级队列上调用pop()将具有从队列中删除顶部元素的效果,而在底层容器上调用clear()将从队列中删除所有元素,而不仅仅是最顶层的。

  

虽然我知道其他方法可以清除它,例如交换或使用空的priority_queue分配它,但我认为如果这段代码能够正常工作,那么它会更有效,因为向量中分配的内存是可重用的。所以我想知道这段代码是否可移植或不会一直有效?

根据reference,底层c成员对象受到保护,因此应该保证在编译器之间访问您的方式,即调用this->c.clear();应该是可移植的(传闻上) ,它适用于旧版OpenBSD上的g++ 4.2.1

就效率而言,它会有所依赖。像this->c.clear();q = priority_queue <int>();这样的内容在内存使用或复杂性方面可能没那么不同,但您必须在不同的平台上进行测试才能进行验证。但是,执行this->c.clear();while(!q.empty()) { q.pop(); }会更有效。

就内存效率而言,优先级队列的pop函数调用底层容器pop_back函数,pop_backclear都不会影响底层向量capacity,所以没有任何“储蓄”可以这样做;尽管如此,如果您有特殊需要,可以调整矢量大小以增加/减少容量。

请记住优先级队列pop函数调用底层容器pop_back函数,而在空容器上调用pop_back未定义的行为

希望可以提供帮助。

答案 1 :(得分:1)

一个非常好的问题。虽然我似乎无法找到任何严格保证它是正确的方法,但有一些理由认为它是。

例如,请考虑operator=的文档:

  

复制赋值运算符。用一份副本替换内容   其他的内容。有效地致电c = other.c;。 (隐式   声明)

由于另一个队列的大小可能不同,这实际上意味着没有内部状态依赖于大小。此外,它还意味着分配一个空队列基本上用空的替换容器,而不做任何其他事情。

考虑到这一点,并且优先级队列的合理实现几乎不需要维护除队列大小之外的任何状态,我相信可以安全地假设清除底层容器是有效的方式清空队列。