【发布时间】:2022-12-05 04:53:23
【问题描述】:
想象一下,我想将 std::unique_ptr 存储在 std::stack 或 std::priority_queue 中。
这些容器有一个top()-函数,它返回一个“const_reference”到顶部元素。这将是对 std::unique_ptr 的 const_reference。
当我们通常想要将所有权从一个std::unique_ptr 转移到另一个时,我们需要移动数据。因此,将其转换为带有 std::move 的右值引用类型。然后移动赋值运算符将完成这项工作(如果有的话)。
我希望到目前为止一切都是正确的。如有不妥请指正。
当我执行典型的 top/pop 组合时,我不能使用 std::move(priorityqueue.top()),因为 top() 返回“const_reference”。
我唯一的想法是抛弃 top() 的常量。我觉得这在某种程度上不是最好的解决方案。
问题:对于这种情况,转让 std::unique_ptr 所有权的正确方法是什么?
我写了下面的例子,只是一个例子,只是一个演示,以更好地理解这个主题,一个 MRE。手头的函数是“getTop2”,它应该从 std::priority_queue 顶部/弹出 2 个元素,然后将这 2 个 std::unique_ptrs 返回给调用者。
请参见:
// Demo example, MRE
#include <iostream>
#include <utility>
#include <memory>
#include <queue>
#include <vector>
struct Foo {
int value{};
Foo() { std::cout << "Calling Foo default constructor\n"; }
Foo(int v) : value(v) { std::cout << "Calling Foo constructor with value " << v << '\n'; }
~Foo() { std::cout << "Calling Foo destructor for Foo with value " << value << "\n\n";
}
};
struct FooDeleter {
void operator ()(Foo* f) {
std::cout << "\nCalling std::priority_queue custom deleter for Foo with value " << f->value << '\n';
delete f;
}
};
using UPtr = std::unique_ptr<Foo, FooDeleter>;
struct Comp { bool operator ()(const UPtr& n1, const UPtr& n2) { return n1->value < n2->value; } };
using PQueue = std::priority_queue<UPtr,std::vector<UPtr>, Comp>;
// ------------------------------------------------------------
std::pair<UPtr, UPtr> getTop2(PQueue& pq) {
UPtr left = std::move(const_cast<UPtr&>(pq.top()));
pq.pop();
UPtr right = std::move(const_cast<UPtr&>(pq.top()));
pq.pop();
return { std::move(left), std::move(right) };
}
// ------------------------------------------------------------
// Demo example, MRE
int main() {
PQueue pq{};
pq.push(UPtr(new Foo(1)));
pq.push(UPtr(new Foo(3)));
pq.push(UPtr(new Foo(2)));
pq.push(UPtr(new Foo(4)));
std::cout << '\n';
while (pq.size() > 1u) {
auto [left, right] = getTop2(pq);
pq.push(UPtr(new Foo(left->value + right->value)));
}
while (pq.size())
pq.pop();
}
正确的“getTop2(pq);”应该如何功能被实现?
并且,作为一个旁节点:我觉得这样的解决方案比使用原始指针更糟糕。但这不是这里的问题。
【问题讨论】:
-
std::stack::top 有一个非常量重载:en.cppreference.com/w/cpp/container/stack/top
-
这对于
std::stack是正确的,但对于std::priority_queue则不正确。在这里做什么?
标签: c++ priority-queue unique-ptr