std :: priority_queue中的比较器

时间:2016-02-04 00:48:16

标签: c++ c++11 stl heap priority-queue

是否有理由std::priority_queue的构造函数通过常量引用接受比较器?如果比较器超出范围怎么办?

在@LightnessRacesInOrbit指出的可能移动比较器的情况下,我正在考虑这个问题!

如果有关于此事的帖子,我很抱歉。我一直都找不到它!

3 个答案:

答案 0 :(得分:8)

我以前从未真正考虑过这个问题,而const-ref确实有点误导。然而,在移动语义出现之前就已经想到了函数签名,并且随着价值接受一切变得时髦。的确,比较器被复制了!

  

[C++14: 23.6.4.1/4]: 效果:使用compx c初始化y(根据需要复制构建或移动构建) ;致电c.insert(c.end(), first, last);,最后致电make_heap(c.begin(), c.end(), comp).

Lambda不是可复制的,但它们可复制构造的,所以这里没有问题。

  

[C++14: 5.1.2/20]: lambda-expression 关联的闭包类型具有已删除(8.4.3)的默认构造函数和已删除的复制赋值运算符。它有一个隐式声明的复制构造函数(12.8),并且可能有一个隐式声明的移动构造函数(12.8)。 [..]

这会阻止比较器本身的移动构造吗?是的,它确实。我将假设这个约定由const-ref然后复制它的比较,源于STL时代,在移动语义之前的方式。我想没有认真考虑添加重载以按比较取值,因为这增加了复杂性,你首先不应该有一个复杂的,可移动的比较器(给它们状态,当然,但不是 )。如果你能提出一个可靠的用例来移动比较器,那么这个可能值得委员会提高。

答案 1 :(得分:5)

它不会超出范围 - 它是复制构造到容器中。有关cppreference.com州的说明:

explicit priority_queue( const Compare& compare = Compare(),
                         const Container& cont = Container() );
  

使用cont的内容复制构造底层容器c。复制 - 构造比较函子comp与compare的内容。调用std :: make_heap(c.begin(),c.end(),comp)。这也是默认构造函数。

构造函数有各种其他形式,但在所有情况下,内部比较器都是从提供的构造函数复制或移动构造的。

答案 2 :(得分:4)

std::priority_queue的构造函数会提供所提供的比较器的副本,因此如果它超出范围,则不会出现问题。

您可以使用lambda作为比较器,方法是使用std::function<bool(const T&, const T&)>作为比较器类型,或直接使用:

auto comp = [](int x, int y) { return x > y; };
std::priority_queue<int, std::vector<int>, decltype(comp)> q(comp);

您可以使用帮助函数来实现此目的:

template<typename T, typename Compare>
auto make_priority_queue(Compare&& comp) {
    return std::priority_queue<T, std::vector<T>, Compare>(std::forward<Compare>(comp));
}

int main() {
    auto q = make_priority_queue<int>([](int x, int y) { return x > y; });
}