排序仿函数 出现 std::priority_queue::push() 的 invalid operator < 异常

首先看一段代码:

#include <queue>
#include <deque>
#include <iostream>

int main()
{
    struct node
    {
        int value;
    };

    struct cmp
    {
        bool operator()( const node& a, const node& b )
        {
            return a.value < b.value;
        }
    };

    std::priority_queue<node, std::deque<node>, cmp > pri_queue;

    node n1 = {22};
    node n2 = {11};
    node n3 = {33};
    node n4 = {11};

    pri_queue.push( n1);
    pri_queue.push( n2);
    pri_queue.push( n3);
    pri_queue.push( n4);

    while( ! pri_queue.empty() )
    {
        node n = pri_queue.top();
        pri_queue.pop();

        std::cout << n.value << std::endl;
    }

    system( "PAUSE");

    return 0;
};

结果输出 最大值优先的 列表:

但如果将  比较器改成:

struct cmp
    {
        bool operator()( const node& a, const node& b )
        {
            return a.value <= b.value;
        }
    };

或者 

struct cmp
    {
        bool operator()( const node& a, const node& b )
        {
            return true;
        }
    };

都会运行异常(当前是 debug 版本):

出现 invalid operator <

原因在于 最后两种的比较器 结果为 true 时是不对称的, 即 如果 A < B 那么对称的应该是 B < A; 即如果 cmp( A, B) 返回true, 那么应该 cmp( B, A) 返回 false, 但不应该

cmp( A, B) = true

cmp( B, A) = true

出现 invalid operator <, 是因为 std::priority_queue 默认使用 less 比较, 如果 A 小于 B 为真, 那么 B 小于 A 就不应该为真,

这里考察

node n2 = {11};
node n4 = {11};

当 调用 push( n4) 时, 必然的要进行排序, 已实现 priority_queue 机制,

检查第一个 cmp 比较器:

struct cmp
    {
        bool operator()( const node& a, const node& b )
        {
            return a.value < b.value;
        }
    };

cmp( n2, n4 ) = false;

cmp( n4, n2 ) = false;

不会同时为 true   , 满足 "结果为true 对称" 条件, 因为这里两个值都为 false.

第二个比较器:

struct cmp
    {
        bool operator()( const node& a, const node& b )
        {
            return a.value <= b.value;
        }
    };

cmp( n2, n4 ) = true;

cmp( n4, n2 ) = true;

同时为 true了, 不对称, 所以在debug版本运行是报错.

第三个比较器 就更加 不对称了:

struct cmp
    {
        bool operator()( const node& a, const node& b )
        {
            return true
        }
    };

cmp( n2, n4 ) = true;

cmp( n4, n2 ) = true;

其实我并没有查看过 std::priority_queue的 排序源码, 只是综合其他开发人员的意见有: 当比较器struct cmp 进行比较获取 true 值时, 预期为获取到理想值(较大者?较小者), 再进行后续操作, 但是在  debug 版本时, 会同时检测 两个 比较元素的 不同 lhs 和 rhs 顺序会不会同时为 true, 是的运行报错, 但这是基于什么严格的 设计理念, 我暂时还未能了解到.

本篇总结为, 在设计 比较器时, 要确保 两个元素 n2 和 n4 的 lhs / rhs 顺序 不会同时 为 true.

原文地址:https://www.cnblogs.com/Wilson-Loo/p/3375325.html