修改unique_ptrs的priority_queue

时间:2014-01-03 16:27:24

标签: c++ c++11 unique-ptr

我正在尝试用C ++编写事件驱动的模拟。现在,它只是基于事件类的unique_ptrs的一个简单的优先级队列:

class Event
{
public:
    double time;
    Event(double time);
    virtual void handle() = 0;
};

struct EventCompare
{
    bool operator()(std::unique_ptr<Event> e1, std::unique_ptr<Event> e2) {
    return e1->time > e2->time;
    }
};

class DumpSimulationEvent : public Event
{
public:
    DumpSimulationEvent(const double time);
    void handle();
};

typedef std::priority_queue<std::unique_ptr<Event>, std::vector<std::unique_ptr<Event>>, EventCompare> EventQueue;

class Simulation
{
    double time;
    EventQueue eventQueue;
public:
    Simulation();
    void run();
};

Event::Event(const double t)
{
    time = t;
}

DumpSimulationEvent::DumpSimulationEvent(const double t) : Event(t)
{
}

void DumpSimulationEvent::handle()
{
    std::cout << "Event time: " << time;
}

Simulation::Simulation()
{
    time = 0;
    eventQueue = EventQueue();
    std::unique_ptr<DumpSimulationEvent> dumpEvent5(new DumpSimulationEvent(5));
  //eventQueue.emplace(dumpEvent5);
}

void Simulation::run()
{
    while (!eventQueue.empty()) {
        std::unique_ptr<Event> currentEvent = std::move(eventQueue.top());
      //eventQueue.pop();
        time += currentEvent->time;
        currentEvent->handle();
    }
}

主要功能(上面未显示)只是创建一个Simulation实例并调用run()方法。问题是取消注释emplace()或pop()会导致

error C2280: 'std::unique_ptr<Event,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function  c:\program files (x86)\microsoft visual studio 12.0\vc\include\xutility 521 1

研究表明,最可能的原因是尝试复制unique_ptr。然而,我不知道它是否是真正的原因,它是否真的发生在评论行或者只是在那里可见。添加std :: move到emplace参数似乎没有帮助。

1 个答案:

答案 0 :(得分:4)

你的问题是你没有正确地移动东西,但是你试图在几个地方制作副本。

这是一个让你的代码工作的差异,有一些评论:

 struct EventCompare
 {
-    bool operator()(std::unique_ptr<Event> e1, std::unique_ptr<Event> e2) {
+    bool operator()(std::unique_ptr<Event> const &e1, std::unique_ptr<Event> const &e2) {
     return e1->time > e2->time;
     }
 };

在这里,正如juanchopanza在他的回答中所提到的,你必须通过引用而不是值来取std::unique_ptr,否则你要求编译器为你制作副本,这是不允许的。

     time = 0;
     eventQueue = EventQueue();
     std::unique_ptr<DumpSimulationEvent> dumpEvent5(new DumpSimulationEvent(5));
-  //eventQueue.emplace(dumpEvent5);
+    eventQueue.emplace(std::move(dumpEvent5));
 }

在上面的代码中,您必须将std::unique_ptr移入队列。 Emplace不会神奇地移动东西,它只是转发构造函数的参数。如果没有std::move,则要求您创建副本。你也可以写一下:eventQueue.emplace(new DumpSimulationEvent(5));并跳过中间对象。

     while (!eventQueue.empty()) {
-        std::unique_ptr<Event> currentEvent = std::move(eventQueue.top());
-      //eventQueue.pop();
+        std::unique_ptr<Event> currentEvent(std::move(const_cast<std::unique_ptr<Event>&>(eventQueu
+        eventQueue.pop();
         time += currentEvent->time;
         currentEvent->handle();

最后,在上面的代码中,您尝试从eventQueue.top()移动,但是您无法从const引用移动,这是top()返回的内容。如果您想强制移动工作,则必须同时使用const_caststd::move()

以下是使用g++-4.8 -std=c++11编译好的完整修改代码:

#include <memory>
#include <queue>
#include <iostream>

class Event
{
public:
    double time;
    Event(double time);
    virtual void handle() = 0;
};

struct EventCompare
{
    bool operator()(std::unique_ptr<Event> const &e1, std::unique_ptr<Event> const &e2) {
    return e1->time > e2->time;
    }
};

class DumpSimulationEvent : public Event
{
public:
    DumpSimulationEvent(const double time);
    void handle();
};

typedef std::priority_queue<std::unique_ptr<Event>, std::vector<std::unique_ptr<Event>>, EventCompare> EventQueue;

class Simulation
{
    double time;
    EventQueue eventQueue;
public:
    Simulation();
    void run();
};

Event::Event(const double t)
{
    time = t;
}

DumpSimulationEvent::DumpSimulationEvent(const double t) : Event(t)
{
}

void DumpSimulationEvent::handle()
{
    std::cout << "Event time: " << time;
}

Simulation::Simulation()
{
    time = 0;
    eventQueue = EventQueue();
    std::unique_ptr<DumpSimulationEvent> dumpEvent5(new DumpSimulationEvent(5));
    eventQueue.emplace(std::move(dumpEvent5));
}

void Simulation::run()
{
    while (!eventQueue.empty()) {
        std::unique_ptr<Event> currentEvent(std::move(const_cast<std::unique_ptr<Event>&>(eventQueue.top())));
        eventQueue.pop();
        time += currentEvent->time;
        currentEvent->handle();
    }
}