2013-10-15 26 views
5

爲什麼我的程序使用STL映射插入值時,鍵已經存在,而不是改變現有的價值?爲什麼stl map插入另一個值,如果鍵已經存在,而不僅僅是改變它?

#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 

爲什麼會出現這種情況,如何解決?

回答

13

std::map用來排序元素的比較函數必須堅持strict weak ordering。但是你的實現不這樣做。根據您的實施,當所有成員(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) 
{ 
    return std::tie(l.a,l.b,l.c) < std::tie(r.a,r.b,r.c); 
} 

std::tie函數返回std::tupleoperator<

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; 
} 

嗯,這仍然是冗長的,你可以實現它實現嚴格的弱排序,所以要利用這個事實。

8

您的operator<()返回true等分要素。

1

您鏈接的代碼在operator <中有錯誤:當密鑰相等時,它返回true。它提供了一個運行時調試斷言'x[CTest(1,1,1)]["lol"] = CTest2(3,4);。如果您將return true;更改爲return false;,它將按預期工作。

1

您的<運算符CTest不正確。如果我的成員都與r的成員相等,您將返回true。如果l == r,它怎麼比r小?基本上這意味着地圖不會將每個CTest(1,1,1)視爲等同的,因此每次分配給它時都會創建一個新的映射。

相關問題