C++ std::map 不同的键寻址同一索引



在进行重构时,我不知何故搞砸了我的代码,所以我使用的 std::map 停止正常工作。

我正在重新组装零碎的 IPv4 数据包。部分解析Packet来了,如果它是数据包的片段,它就会变成Fragment,它具有重新组装的功能。

...    
if(packet.isIPv4() && packet.isFragment()){
    auto keyForMap = packet.key();
    auto it = fragments.find(keyForMap);
    auto fragmentNotFound = fragments.end();
    std::cout << "-----------------------"  << std::endl;        
    std::cout << "Fragments len: " << fragments.size() << std::endl;        
    keyForMap.print();
    if(it == fragmentNotFound){
        std::cout << "Not Found" << std::endl;
        fragments[keyForMap] = Fragment(packet);
    } else {
        std::cout << "Found" << std::endl;
        fragments[keyForMap].add(packet);
        /* reassembling function call and some processing */
        }
    }
}
...

使用的数据类型: IPv4 std::array<uchar_t, 4>

fragments fragments_t &

fragments_t std::map<FragmentCommon, Fragment>

struct FragmentCommon{
    FragmentCommon(IPv4 ipsrc,
                   IPv4 ipdst,
                   uchar_t protocol,
                   uint16_t identification) : ip_src(ipsrc),
                                              ip_dst(ipdst),
                                              protocol(protocol),
                                              identification(identification){};
    void print(){
        printf("key>%d.%d.%d.%d ", ip_src[0], ip_src[1], ip_src[2], ip_src[3]);
        printf("%d.%d.%d.%d ", ip_dst[0], ip_dst[1], ip_dst[2], ip_dst[3]);
        printf("%d %dn", protocol, identification);
    };
    IPv4 ip_src;
    IPv4 ip_dst;
    uchar_t protocol;
    uint16_t identification;
};
static bool operator<(const struct FragmentCommon &lhs, const struct FragmentCommon &rhs){
    return lhs.ip_dst         < rhs.ip_dst &&
           lhs.ip_src         < rhs.ip_src &&
           lhs.protocol       < rhs.protocol &&
           lhs.identification < rhs.identification;
}

这是我的代码给我的输出:

-----------------------
Fragments len: 0 // Correct (this is first fragment so nothing is in map)
key>192.168.1.3 192.168.1.4 6 1
Not Found // So it's added into map
-----------------------
Fragments len: 1 // Correct (1st fragment is in map)
key>192.168.1.5 192.168.1.6 6 1
Found // Not correct...keys are different
-----------------------
Fragments len: 1
key>192.168.1.5 192.168.1.6 6 1
Found
-----------------------
Fragments len: 1
key>192.168.1.5 192.168.1.6 6 1
Found
-----------------------

鉴于您在问题中发布和陈述的内容,由于IPv4是一个std::array<uchar_t,4>(我假设uchar_tunsigned char的别名),您可以使用std::tie为FragmentCommon定义operator <

在以"级联"方式处理要测试的多个值时,使用 std::tie 更简单且更不容易出错来定义严格-弱排序std::map键需要)。

#include <tuple>
//...
static bool operator < (const struct FragmentCommon &lhs, const struct FragmentCommon &rhs)
{
    return std::tie(lhs.ip_dst, lhs.ip_src, lhs.protocol, lhs.identification) < 
           std::tie(rhs.ip_dst, rhs.ip_src, rhs.protocol, rhs.identification);
}

由于 std::array 定义了运算符<,因此在每个std::tie中使用所有 4 个参数时,使用 std::tie 可以正常工作。

最新更新