如何在两个 STL 容器之间移动 unique_ptr 对象

how to move unique_ptr object between two STL containers

#include <utility>
#include<unordered_map>
#include<queue>
using namespace std;


struct Task {
    char t;
    int cnt;
    Task(char ch, int cnt):t(ch), cnt(cnt){};
};
struct CompTask {
    bool operator() (const unique_ptr<Task>& a, const unique_ptr<Task>& b) {
        return a->cnt < b->cnt;
    }
};
class Schedule {
public:
    int schedule() {
        unordered_map<unique_ptr<Task>, int> sleep_q;
        priority_queue<unique_ptr<Task>, vector<unique_ptr<Task>>, CompTask> ready_q; // max heap
        ready_q.push(std::make_unique<Task>('A', 1));

        auto& ptr = ready_q.top();
        //sleep_q.insert({ptr, 1}); // compile error 
        sleep_q.insert({std::move(ptr), 1}); // compile error 
        // some other code...
        
        return 1;
    }
};
int main() {
    return 0;

}
// error:
cpp:38:17: error: no matching member function for call to 'insert'
        sleep_q.insert({std::move(ptr), 1}); // compile error 
        ~~~~~~~~^~~~~~

编程上下文: 我有一个任务 class 并且程序尝试模拟任务调度(这涉及在就绪队列和睡眠队列之间来回移动任务)。 我有两个标准容器分别用于就绪队列和睡眠队列,priority_queue 的值类型为 unique_ptr<Task>,另一个是 unorder_map(休眠队列)其key也是unique_ptr<Task>。我在将 unique_ptr 对象从 priorty_queue 移动到 unordered_map 时遇到了问题(如代码所示)。

我的问题是: (1) 如何将项目插入 unordered_map,我在这样做时遇到了编译错误。 (2) 在问题上下文中,首选哪种类型的“指针”? unique_ptr<Task>, shared_ptr<Task>, or just Task*

要在 std 容器之间移动 unique_ptr 需要销毁一个 unique_ptr(存储在第一个 std 容器中)并将支持数据传递给新的 unique_ptr。这可以用 std::move 来完成。但是,通常使用 shared_ptr 更容易。这通过允许 shared_ptr 指向同一个任务同时位于两个 std 容器中来避免问题。哪怕只是一瞬间。

但是,由于您可能有多个 shared_ptr 对象指向同一个任务,因此 shared_ptr 无法唯一标识该任务。为此,我建议为每个任务创建一个任务 ID。只要您保证它对于该任务是唯一的,一个简单的整数就可以解决这个问题。整数任务 Id 可以很好地与地图配合使用,因为 Id 可以用作键。

std::priority_queue<> 似乎缺少移动功能。您可以使用 const_cast 绕过它,但在极少数情况下它可能会导致未定义的行为(当存储的元素类型为 const 时)。

    int schedule() {
        unordered_map<unique_ptr<Task>, int> sleep_q;
        priority_queue<unique_ptr<Task>, vector<unique_ptr<Task>>, CompTask> ready_q; // max heap                                                                                                     
        ready_q.push(std::make_unique<Task>('A', 1));

        unique_ptr<Task> ptr = 
                std::move(const_cast<unique_ptr<Task>&>(ready_q.top()));
        //                ^ Here. priority_queue::top() returns `const&`.
        ready_q.pop(); // remove moved element from priority_queue
        sleep_q.insert(std::make_pair(std::move(ptr), 1));                                                                                                                          
        // some other code...                                                                                                                                                                         

        return 1;
    }

参考:This answer