如何从priority_queue中提取unique_ptr并维护所有权语义

时间:2017-10-28 21:07:42

标签: c++ stl unique-ptr

我在priority_queue中有一个unique_ptr,我想从该集合中删除它并将其放在双端队列中,同时保持unique_ptr的所有权语义。但是我找不到一种方法可以在没有编译错误的情况下将其从priority_queue中拉出来:“尝试引用已删除的函数”。什么是实现这一目标的正确方法?

struct MyStruct {
    int val = 2;

    MyStruct(const int val) : val(val) {}
};

void testDeque() {
    std::priority_queue<std::unique_ptr<MyStruct>> q1;
    q1.emplace(std::make_unique<MyStruct>(10));
    std::deque<std::unique_ptr<MyStruct>> q2;
    q2.push_back(q1.top()); // <- compiler error "attempting to reference a deleted function"
    q2.push_back(std::move(q1.top())); // <- compiler error "attempting to reference a deleted function"
    q1.pop();
}

3 个答案:

答案 0 :(得分:1)

制作自己的堆。所有堆函数都已经在<algorithm>标题中。

std::vector<std::unique_ptr<MyStruct>> q1;

auto push = [&q1](std::unique_ptr<MyStruct> p) {
    q1.push_back(std::move(p));
    std::push_heap(q1.begin(), q1.end());
};

auto pop = [&q1]() {
    std::pop_heap(q1.begin(), q1.end());
    auto result = std::move(q1.back());
    q1.pop_back();
    return result;
};

push(std::make_unique<MyStruct>(10));
std::deque<std::unique_ptr<MyStruct>> q2;
q2.push_back(pop());

答案 1 :(得分:0)

如果priority_queue::top返回了非const引用,则用户可以更改元素的值,从而破坏使其工作的priority_queue内部不变量。引用cppreference

  

使用priority_queue类似于在某个随机访问容器中管理堆,其好处是 无法意外地使堆无效

所以,你的priority_queuestd::move(q1.top())q1.pop()之间处于无效状态:移动后指针为空,所以它实际上是现在最小的元素,而不是最大元素,违反了班级不变量。虽然这可能在实践中起作用,但依赖于实现细节而不是依赖于记录的行为通常是不好的。

您可以根据priority_queue中的std::heap*函数编写自己的<algorithm>,正如Benjamin Lindley在其帖子中建议的那样,可以更改存储的值。或者,您可以使用某些已排序的容器,例如std::set,从而牺牲堆的好处。

答案 2 :(得分:-1)

top返回无法移动的const_reference时,您应该const_cast

q2.push_back(std::move(const_cast<std::unique_ptr<MyStruct>&>(q1.top())));

move左对象处于有效状态,因此关注q1.pop()是完全安全的。