1

I am trying to add key & value data to my class map member variable - but it does not adds the same -I tried map - insert, [] and emplace method but they are not adding data to map in my loop code - only the value I have inserted during my class construction is available in it - what I need to do to fix the issue - I was expecting that the show method will also print 7, 8,9, 9 -

#include <iostream>
#include <map> 
#include <vector>

  class A {
    public:
      A(std::initializer_list <uint32_t> d): data(d) {}
    std::vector <uint32_t> data;
    bool operator < (const A & rhs) const {
      size_t rhsSize = rhs.data.size();
      for (size_t i = 0; i < data.size(); i++) {
        if (i < rhsSize)
          return false;
        return true;
      }
    }
  };

class B {
  public:
    B(const std::map <A, uint32_t> & t): table(t) {}
  void Show() {
    for (std::map <A, uint32_t> ::iterator it = table.begin(); it != table.end(); ++it) {
      for (const auto & i: it->first.data)
        std::cout << i << "\n";
      std::cout << it->second << "\n";
    }
  }

  std::map <A, uint32_t> table;
};

int main() {
  std::map <A, uint32_t> tb = {
    {
      A {70, 8, 9,10}, 1234}
  };
  B b(tb);
  for (int i = 0; i < 2; i++) {
    b.Show();
    b.table.emplace(A {7, 8,9, 9}, 1234);
  }
  return 0;
}

Compile and run the code:

$ c++ -std=c++11 try78.cpp


$ ./a.exe
70
8
9
10
1234
70
8
9
10
1234
Programmer
  • 8,303
  • 23
  • 78
  • 162
  • 3
    `A`'s `operator <` doesn't make sense to me. `i < rhsSize` is certainly true unless `rhs` is empty. Talk this one through with [your Rubber Duck](https://en.wikipedia.org/wiki/Rubber_duck_debugging). Plus no `return` statement at all if `this` is empty. – user4581301 Feb 12 '19 at 18:25
  • Thanks I made the A's operator < to return true and the data got added - how can I ensure that even if it return false the data can be added? – Programmer Feb 12 '19 at 18:28
  • 2
    I know this is a matter of taste, but the whitespace arount the `<` and `>` tokens of your templates is really parsed by my brain as less-than and greater-than operators. – YSC Feb 12 '19 at 18:28
  • 1
    Cannibalized notes from my now-redundant answer: `map` requires [Strict Weak Ordering](https://en.wikipedia.org/wiki/Weak_ordering). [This answer](https://stackoverflow.com/a/981299/4581301) gives great set of quick examples. – user4581301 Feb 12 '19 at 18:35

1 Answers1

6

Your operator < violates the strict weak ordering requirement that std::map requires of the key. That requires that if comp(a,b) is true then comp(b,a) is false. You use

bool operator < (const A & rhs) const {
  size_t rhsSize = rhs.data.size();
  for (size_t i = 0; i < data.size(); i++) {
    if (i < rhsSize)
      return false;
    return true;
  }
}

to compare the elements and if we compare {70, 8, 9,10} against {7, 8,9, 9} then it returns true and if we flip it around it also returns true. This makes the map think the elements are equal and it won't add the second item.

If you just to make sure that unique vectors are stored in the map then you can use std::vector's operator < in A's operator < like

bool operator < (const A & rhs) const {
    return data < rhs.data;
}

and the code will function properly.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • 1
    Thanks for the explanation - I just modified the code as suggested and it works as expected - is it that the operator < method will be called twice and if and if only both of its call times the values are complimentary the data will be inserted in the map – Programmer Feb 12 '19 at 18:40
  • 2
    @Programmer Yes. Since keys have to be unique in a map if `cmp(a, b) == cmp(b, a)` then the elements "have to be the same" since that is the only value in an totally ordered set that has that behavior. – NathanOliver Feb 12 '19 at 18:43