优先队列中自定义比较器的访问冲突
Access violation in custom comparator in priority queue
我有一个问题是我的一个程序引发了访问冲突。
通过调试,我发现由于某种原因,比较器函数为空。
但是我不确定为什么会这样或如何解决它。
我创建了一个最小工作示例来重现该问题:
#include "Tryout.h"
#include <queue>
struct Event {
uint64_t mv_timeout;
};
bool CompareEvents(const Event& a, const Event& b) {
return a.mv_timeout < b.mv_timeout;
}
int main() {
std::priority_queue<Event, std::vector<Event>, decltype(&CompareEvents)> mt_eventQueue;
Event lo_event1{
.mv_timeout = 1,
};
Event lo_event2{
.mv_timeout = 2,
};
mt_eventQueue.push(lo_event1);
mt_eventQueue.push(lo_event2);
return 0;
}
添加第二个事件时执行崩溃。
Exception thrown at 0x0000000000000000 in Tryout.exe: 0xC0000005:
Access violation executing location 0x0000000000000000.
如前所述,比较函数似乎是空的,即使我通过模板传递它也很困难。
这里出了什么问题?
您需要在构造函数中显式指定比较函数
std::priority_queue<Event, std::vector<Event>, decltype(&CompareEvents)> mt_eventQueue( CompareEvents );
否则默认参数将用于产生空指针的比较函数。
使用的构造函数具有以下带有默认参数的声明
explicit priority_queue(const Compare& x = Compare(), Container&& = Container());
比较器函数的模板参数仅提供函数的类型,您仍然需要提供与该类型匹配的实际函数到 std::priority_queue
的实例(通过其 constructor)。
如果您自己定义一个小于运算符,那么您不需要为 std::priority_queue
.
显式提供任何其他模板参数
例如:
struct Event
{
uint64_t mv_timeout;
};
bool operator<(const Event &a, const Event &b)
{
return a.mv_timeout < b.mv_timeout;
}
int main()
{
std::priority_queue<Event> mt_eventQueue;
Event lo_event1{
.mv_timeout = 1,
};
Event lo_event2{
.mv_timeout = 2,
};
mt_eventQueue.push(lo_event1);
mt_eventQueue.push(lo_event2);
return 0;
}
只要你的比较器函数不是 functor,你应该在 std::priority:queue
的构造函数中传递你的比较器函数。
std::priority_queue<Event, std::vector<Event>, decltype(&CompareEvents)> mt_eventQueue(CompareEvents);
如果你的比较器是这样的
struct CompareEvents
{
bool operator()(const Event& a, const Event& b) {
return a.mv_timeout < b.mv_timeout;
}
}
您可以在不指定仿函数的情况下创建队列,只要它由 CompareEvents
的默认构造函数推导出来(如 here 所述)。
std::priority_queue<Event, std::vector<Event>, CompareEvents> mt_eventQueue; //this works
我有一个问题是我的一个程序引发了访问冲突。 通过调试,我发现由于某种原因,比较器函数为空。 但是我不确定为什么会这样或如何解决它。
我创建了一个最小工作示例来重现该问题:
#include "Tryout.h"
#include <queue>
struct Event {
uint64_t mv_timeout;
};
bool CompareEvents(const Event& a, const Event& b) {
return a.mv_timeout < b.mv_timeout;
}
int main() {
std::priority_queue<Event, std::vector<Event>, decltype(&CompareEvents)> mt_eventQueue;
Event lo_event1{
.mv_timeout = 1,
};
Event lo_event2{
.mv_timeout = 2,
};
mt_eventQueue.push(lo_event1);
mt_eventQueue.push(lo_event2);
return 0;
}
添加第二个事件时执行崩溃。
Exception thrown at 0x0000000000000000 in Tryout.exe: 0xC0000005: Access violation executing location 0x0000000000000000.
如前所述,比较函数似乎是空的,即使我通过模板传递它也很困难。
这里出了什么问题?
您需要在构造函数中显式指定比较函数
std::priority_queue<Event, std::vector<Event>, decltype(&CompareEvents)> mt_eventQueue( CompareEvents );
否则默认参数将用于产生空指针的比较函数。
使用的构造函数具有以下带有默认参数的声明
explicit priority_queue(const Compare& x = Compare(), Container&& = Container());
比较器函数的模板参数仅提供函数的类型,您仍然需要提供与该类型匹配的实际函数到 std::priority_queue
的实例(通过其 constructor)。
如果您自己定义一个小于运算符,那么您不需要为 std::priority_queue
.
例如:
struct Event
{
uint64_t mv_timeout;
};
bool operator<(const Event &a, const Event &b)
{
return a.mv_timeout < b.mv_timeout;
}
int main()
{
std::priority_queue<Event> mt_eventQueue;
Event lo_event1{
.mv_timeout = 1,
};
Event lo_event2{
.mv_timeout = 2,
};
mt_eventQueue.push(lo_event1);
mt_eventQueue.push(lo_event2);
return 0;
}
只要你的比较器函数不是 functor,你应该在 std::priority:queue
的构造函数中传递你的比较器函数。
std::priority_queue<Event, std::vector<Event>, decltype(&CompareEvents)> mt_eventQueue(CompareEvents);
如果你的比较器是这样的
struct CompareEvents
{
bool operator()(const Event& a, const Event& b) {
return a.mv_timeout < b.mv_timeout;
}
}
您可以在不指定仿函数的情况下创建队列,只要它由 CompareEvents
的默认构造函数推导出来(如 here 所述)。
std::priority_queue<Event, std::vector<Event>, CompareEvents> mt_eventQueue; //this works