简体   繁体   English

无法使用struct作为键在C ++映射中查找插入的值

[英]Cant find inserted values in C++ map using struct as key

I'm trying to use a map to store map information using coordinates x,y as key. 我正在尝试使用地图以坐标x,y作为键来存储地图信息。 I cant iterate properly trough this map using the auto iterator or map.find(). 我无法使用自动迭代器或map.find()正确地遍历此地图。 It just wont return me the correct map value. 它只是不会返回我正确的地图值。 I'm using C++14, here is my chunk of code: 我正在使用C ++ 14,这是我的代码块:

#include <iostream>
#include <string>
#include <map>
#include <iterator>
#include <vector>

using namespace std;

struct mapPoint {
  int X;
  int Y;

  bool operator < (const mapPoint &coord) const {
    if (X == coord.X && Y == coord.Y) {
      return true;
    } else {
      return false;
    }
  }
};

struct explorerNotes {
  bool foundCoin;
  int timesVisitedThisBlock;
  vector<bool> unexploredEntrances; // 0 0 0 0 -> N S E W
  explorerNotes():timesVisitedThisBlock(0),unexploredEntrances(4,false){}
};

int main() {
  map<mapPoint, explorerNotes> explorerNotebook;

  explorerNotes testNote1, testNote2, testNote3;
  mapPoint testCoord1, testCoord2, testCoord3;

  testNote1.foundCoin = true;
  testNote1.timesVisitedThisBlock = 42;
  testNote1.unexploredEntrances = {true, true, false, false};
  testCoord1.X = 25;
  testCoord1.Y = 3;

  testNote2.foundCoin = false;
  testNote2.timesVisitedThisBlock = 314;
  testNote2.unexploredEntrances = {false, true, false, false};
  testCoord2.X = 11;
  testCoord2.Y = 2;

  testNote3.foundCoin = true;
  testNote3.timesVisitedThisBlock = 420;
  testNote3.unexploredEntrances = {false, true, false, false};
  testCoord3.X = 1;
  testCoord3.Y = 1;

  explorerNotebook.insert(pair<mapPoint, explorerNotes>(testCoord1, testNote1));
  explorerNotebook.insert(pair<mapPoint, explorerNotes>(testCoord2, testNote2));
  explorerNotebook.insert(pair<mapPoint, explorerNotes>(testCoord3, testNote3));

  map<mapPoint, explorerNotes>::iterator p;
  p = explorerNotebook.find(testCoord1);
  cout << " testing 1:"
       << "\nfoundCoin: " << p->second.foundCoin
       << "\ntimesVisitedThisBlock: " << p->second.timesVisitedThisBlock
       << "\nunexploredEntrances: "<< "(" << p->second.unexploredEntrances[0] << "," << p->second.unexploredEntrances[1] << "," << p->second.unexploredEntrances[2] << "," <<p->second.unexploredEntrances[3] << ")" << endl;

  map<mapPoint, explorerNotes>::iterator q;
  q = explorerNotebook.find(testCoord2);
  cout << " testing 2:"
       << "\nfoundCoin: " << q->second.foundCoin
       << "\ntimesVisitedThisBlock: " << q->second.timesVisitedThisBlock
       << "\nunexploredEntrances: "<< "(" << q->second.unexploredEntrances[0] << "," << q->second.unexploredEntrances[1] << "," << q->second.unexploredEntrances[2] << "," <<q->second.unexploredEntrances[3] << ")" << endl;

  map<mapPoint, explorerNotes>::iterator r;
  r = explorerNotebook.find(testCoord3);
  cout << " testing 3:"
       << "\nfoundCoin: " << r->second.foundCoin
       << "\ntimesVisitedThisBlock: " << r->second.timesVisitedThisBlock
       << "\nunexploredEntrances: "<< "(" << r->second.unexploredEntrances[0] << "," << r->second.unexploredEntrances[1] << "," << r->second.unexploredEntrances[2] << "," <<r->second.unexploredEntrances[3] << ")" << endl;;

  return 0;
}

When I compile this code it gave me the output: 当我编译这段代码时,它给了我输出:

 testing 1:
foundCoin: 1
timesVisitedThisBlock: 42
unexploredEntrances: (1,1,0,0)
 testing 2:
foundCoin: 1
timesVisitedThisBlock: 42
unexploredEntrances: (1,1,0,0)
 testing 3:
foundCoin: 1
timesVisitedThisBlock: 42
unexploredEntrances: (1,1,0,0)

It just repeats the first added value...I'm stuck all day. 它只是重复第一个增加的价值...我整日呆滞。 Any ideas? 有任何想法吗? Thanks in advance. 提前致谢。

Your operator < is completely messed up. 您的operator <完全被搞砸了。

You are saying that A is less than B if its X coordinate is equal and its Y coordinate is equal. 您说的是,如果A的X坐标等于Y坐标,则A小于B。 So (1,1) < (2,2) is false, but (1,1) < (1,1) is true. 因此(1,1)<(2,2)为假,但(1,1)<(1,1)为真。 No wonder the map can't manage to find the right entry. 难怪地图无法找到正确的条目。

In particular: 尤其是:

  • since (1,1) < (2,2) is false, and (1,1) > (2,2) is false (> being < with the arguments reversed), that means (1,1) and (2,2) must be equal! 由于(1,1)<(2,2)为假,(1,1)>(2,2)为假(>为<且参数取反),表示(1,1)和(2, 2)必须相等!
  • since (1,1) < (1,1) is true, (1,1) > (1,1) can't be true, because one thing can't be less than and greater than another thing. 因为(1,1)<(1,1)为真,所以(1,1)>(1,1)不能为真,因为一件事不能小于和大于另一件事。 Yet it is. 是的

You need to figure out an actual order for the points, and implement that order in operator < . 您需要找出这些点的实际顺序,并在operator <实现该顺序。 For example, you could say that (a,b) < (c,d) if a<c, or if a==c and b<d. 例如,如果a <c,或者a == c且b <d,则可以说(a,b)<(c,d)。 Then you get that (1,1) < (1,2) < (1,3) < (2,0) < (2,1) < ... 然后得到(1,1)<(1,2)<(1,3)<(2,0)<(2,1)<...

bool operator < (const mapPoint &coord) const {
    if (X < coord.X || (X == coord.X && Y < coord.Y)) {
        return true;
    } else {
        return false;
    }
}

Your < does not qualify as a strict weak ordering. 您的<不符合严格的弱排序要求。 So your code does UB once put in the map. 因此,一旦您将代码放入地图,UB便会这样做。

The easy way to write a conforming < is: 编写符合的<的简单方法是:

friend auto mytie(const mapPoint& self){
  return std::tie(self.X, self.Y);
}
friend bool operator<(const mapPoint& lhs, const mapPoint& rhs){
  return mytie(lhs)<mytie(rhs);
}

Where we delegate < to tuple 's implementation without copies and with maximal DRY (don't repeat yourself). 我们将<委托给tuple的实现,该实现不带副本且具有最大DRY(请勿重复)。

I find doing < manually is easy, but error prone over the decades. 我发现手动执行<很容易,但是数十年来容易出错。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM