【问题标题】:How to move elements out of STL priority queue如何将元素移出 STL 优先级队列
【发布时间】:2025-12-18 07:40:01
【问题描述】:

C++ 的 STL 优先级队列有一个 void pop() 方法和一个 const ref top() 方法。因此,如果要将元素移出队列,则必须执行以下操作:

T moved = std::move(const_cast<T&>(myQueue.top())));
myQeue.pop();

这有效地将顶部转换为非常量,以便可以移动(而不是复制)它。我不喜欢这段代码,因为强制移动可能会使优先级队列的不变量无效,这应该因为弹出而不重要,但事情可能出错。

有没有更好的方法来完成弹出/移动? 为什么没有 T&& top_and_pop() 函数?

【问题讨论】:

  • 你不是在移动top函数返回的副本吗?为什么要这样做?它会阻止任何 RVO - 你想达到什么目标?
  • Top 返回一个 (const) 引用。在这种特殊情况下,我想将对象从优先级队列移动到向量。但这并不重要。
  • 我不确定,但看起来,在 C++03 的上下文中,top_and_pop 没有多大意义,因为在任何情况下都只能有副本,所以添加一个方便的方法没有任何性能差异,只少了一行代码,似乎没有必要。现在有了移动语义和可以移动底层容器的成员,这似乎是有道理的,但接口没有得到任何改变......我也很好奇为什么。

标签: c++ c++11 move-semantics c++03


【解决方案1】:

std::priority_queue 基本上是堆算法之上的一个薄层。您可以通过以下方式轻松创建自己的优先级队列

使用这些构建块,实现起来很简单,您可以轻松实现移动弹出操作。以下清单包含一个最小的工作实现:

template <typename Type, typename Compare = std::less<Type>>
class queue
{
private:
    std::vector<Type> _elements;
    Compare _compare;
public:
    explicit queue(const Compare& compare = Compare())
        : _compare{compare}
    { }
    void push(Type element)
    {
        _elements.push_back(std::move(element));
        std::push_heap(_elements.begin(), _elements.end(), _compare);
    }
    Type pop()
    {
        std::pop_heap(_elements.begin(), _elements.end(), _compare);
        Type result = std::move(_elements.back());
        _elements.pop_back();
        return std::move(result);
    }
};

【讨论】:

  • +1 我还应该检查/static_assert 是否为is_nothrow_move_constructible(即使在最小实现中),否则您可能会丢失pop 中的一个元素。
  • 这应该可以完成工作,但它非常冗长。
  • std::move 中的return std::move(result) 是多余的。
【解决方案2】:

这确实是std::priority_queue 的一个缺陷。但是您可以像这样轻松扩展它:

template <
    class T,
    class Container = std::vector<T>,
    class Compare = std::less<typename Container::value_type>>
class priority_queue : public std::priority_queue<T, Container, Compare> {
public:
  T top_and_pop() {
    std::pop_heap(c.begin(), c.end(), comp);
    T value = std::move(c.back());
    c.pop_back();
    return value;
  }

protected:
  using std::priority_queue<T, Container, Compare>::c;
  using std::priority_queue<T, Container, Compare>::comp;
};

(基于@nosid 的回答)

【讨论】: