我在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();
}
答案 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_queue
在std::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()
是完全安全的。