2016-09-25 88 views
5

任何人都可以解釋我從這個簡單的程序使用std::map得到的輸出。請注意,我將p插入到地圖中,但不是q,但它表示它們都找到了它們,但也說地圖中只有1個元素!std :: map的作用是什麼?

#include <map> 
#include <iostream> 

struct screenPoint { 
    float x = 0, y = 0; 
    screenPoint(float x_, float y_): x{x_}, y{y_}{} 
}; 

bool operator<(const screenPoint& left, const screenPoint& right){ 
    return left.x<right.x&&left.y<right.y; 
} 

std::map<screenPoint, float> positions; 

int main(int argc, const char * argv[]) { 

    auto p = screenPoint(1,2); 
    auto q = screenPoint(2,1); 
    positions.emplace(p,3); 

    auto f = positions.find(p); 
    auto g = positions.find(q); 

    if (f == positions.end()){ 
    std::cout << "f not found"; 
    } else { 
    std::cout << "f found"; 
    } 

    std::cout << std::endl; 

    if (g == positions.end()){ 
    std::cout << "g not found"; 
    } else { 
    std::cout << "g found"; 
    } 

    std::cout << std::endl; 

    std::cout << "number elements: " << positions.size() << "\n"; 
    return 0; 
} 

輸出:

f found 
g found 
number elements: 1 
+0

條件應該是'left.x 0x499602D2

+0

比較實際上對你有意義嗎(從某種意義上說,你真的附加了哪個對象比另一個對象更小的意思),還是這只是一種使用字典的手段? –

+0

@AmiTavory我只想要一本字典;我不在乎訂購 –

回答

5

問題是與你所定義的比較仿函數,在這種情況下的方式。兩個元素pq具有相同的xy,只是倒過來。 您的邏輯檢查其中一個的x小於另一個,以及y s。對於這些輸入,這永遠不會評估爲true

試試這個片斷:

int main() 
{ 
    auto p = screenPoint(1,2); 
    auto q = screenPoint(2,1); 

    std::cout << std::boolalpha << (p < q) << " " << (q < p) << std::endl; 
} 

它會打印出

false false 

所以p不小於q,並q不小於p。就地圖而言,這使得它們相當。

+0

我沒有看到有不正確的平等點;如果雙打不是按位相等,他們不會散列不同?在這種情況下,無論寫入的平等程度如何,查找最有可能無效。你需要散列函數服從與等號相同的ε,並且afaik不能保證std :: hash將以這種方式寫入。 –

+0

感謝您的幫助;我已經發布了一個相關的問題:http://stackoverflow.com/questions/39796763/why-is-this-stdmap-key-not-getting-found –

3

爲了在std::map中使用數據類型,它必須具有稱爲嚴格弱排序(https://en.wikipedia.org/wiki/Weak_ordering)的特定排序。這意味着不平等運算符(<)服從一組非常特定的規則。然而,您指定的操作員不是一個弱順序。特別是,假設分別由(1,2)和(2,1)構建的兩個screenPoint s,ab,您將看到它既是a < b也是b < a。在嚴格的弱排序中,這將暗示a == b,這是不正確的!

由於您的不平等運算符不符合嚴格弱排序的要求,因此最終會做出意想不到的事情。我建議閱讀關於這種排序的更多細節,並閱讀/思考爲什麼地圖需要它。在短期內,您可以重新定義您的運營商,如下所示:

bool operator<(const screenPoint& left, const screenPoint& right){ 
    if (left.x != right.x) return left.x < right.x; 
    else return (left.y < right.y); 
} 
+1

它需要是一個嚴格的弱排序,具體而言。 –

+0

@LightnessRacesinOrbit編輯,謝謝。 –

+0

如果我實際上不關心訂購,也許地圖不是最好的容器?也許unordered_map?但後來我會遇到另一個問題,我不得不散列我的自定義結構,對吧? –