5

为什么我的程序使用 STL 映射在键已经存在时插入值而不是更改现有值?

#include <iostream>
#include <map>

using namespace std;

struct CTest
{
    int a, b, c;
    CTest(int A, int B, int C) : a(A), b(B), c(C) {}
};

bool operator<(const CTest & l, const CTest & r)
{
    if(l.a < r.a) return true;
    else if(l.a > r.a) return false;

    if(l.b < r.b) return true;
    else if(l.b > r.b) return false;

    if(l.c < r.c) return true;
    else if(l.c > r.c) return false;

    return true;
}

struct CTest2
{
    bool operator<(const CTest2 & r) const
    {
        return q < r.q && w < r.w;
    }
    int q,w;
    CTest2() : q(0), w(0) {}
    CTest2(int Q, int W) : q(Q), w(W) {}
};

int main()
{
    // map of maps
    map<CTest, map<string, CTest2> > x;

    x[CTest(1,1,1)]["lol"] = CTest2(1,2); // x[CTest(1,1,1)]["lol"] now stores CTest2(1,2)
    x[CTest(1,1,1)]["lol"] = CTest2(3,4); // CTest2(1,2) must be changed to CTest2(3,4)
    x[CTest(1,1,1)]["lol"] = CTest2(5,6); // now to CTest2(5,6)

    x[CTest(2,1,0)]["ha"] = CTest2(11,12);

    for(map<CTest, map<string, CTest2> >::iterator i = x.begin(); i != x.end(); ++i)
        for(map<string, CTest2>::iterator j = i->second.begin(); j != i->second.end(); ++j)
            cout << j->first << " " << j->second.q << " " << j->second.w << endl;
}

运行此打印:

lol 3 4
lol 1 2
ha 11 12

为什么会发生这种情况,我该如何解决?

4

4 回答 4

13

std::map用于对元素进行排序的比较函数必须遵守严格的弱排序。但是你的实现并没有做到这一点。根据您的实施,当所有成员 (a, b, c)相等时,您的operator<回报true. 换句话说,(1,1,1) < (1,1,1)返回true。是否有意义?不。

一个简单的解决方法是:

bool operator<(const CTest & l, const CTest & r)
{
    if(l.a < r.a) return true;
    else if(l.a > r.a) return false;

    if(l.b < r.b) return true;
    else if(l.b > r.b) return false;

    return l.c < r.c;
}

那太冗长了。而不是<,如果您使用!=,上述内容将简化为:

bool operator<(const CTest & l, const CTest & r)
{
    if(l.a != r.a) return l.a < r.a;
    else if(l.b != r.b) return l.b < r.b;
    return l.c < r.c;
}

好吧,这仍然很冗长,您可以将其实现为:

bool operator<(const CTest & l, const CTest & r)
{
   return std::tie(l.a,l.b,l.c) < std::tie(r.a,r.b,r.c);
}

std::tie函数返回std::tupleoperator<实现的弱排序,因此利用这一事实。

于 2013-10-15T12:58:51.507 回答
8

等量元素的operator<()回报true

于 2013-10-15T12:58:47.843 回答
1

您链接的代码有一个错误operator <:它true在键相等时返回。它在'x[CTest(1,1,1)]["lol"] = CTest2(3,4);. 如果您更改return true;return false;,它将按预期工作。

于 2013-10-15T13:00:17.797 回答
1

您的 CTest < 运算符不正确。如果 l 的成员都等于 r 的成员,则返回 true。如果 l == r,它如何小于 r ?基本上这意味着地图不会将每个 CTest(1,1,1) 视为等效的,因此每次分配给它时都会创建一个新的映射。

于 2013-10-15T13:02:10.950 回答