我正在尝试用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参数似乎没有帮助。
答案 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_cast
和std::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();
}
}