sthbuilder
sthbuilder

Reputation: 573

Troubling adding to a map

I am trying to build a map with a custom comparator, however, something that I can not figure it out goes wrong, being unable to add item to the map (specifically, can only add the first item)

struct byKey
{
    bool operator () ( const Key &key1, const Key &key2) const {
        return key1.keytoInt() < key2.keytoInt();
    }
};

where Key class has a private char[5], like

char[0]=1, char[1]=2, char[3]=13, char[4]=20, char[5]=28

there is a matching going that ensures all the character in char digit[5] (is less than 32) and can be converted to a character.like char=0, it will search a table, find a character like A

I use a method in Key to covert it to int, then compare with int

int Key ::  keytoInt() const{
    int sum;
    sum=atoi(digit);
    return sum;
}

I build a table of map with key and value both as Key type, however, when trying to test it, I can not add items to the table, I am not sure where goes wrong.

No compile error, however, logically, even though I have inserted into the map three times, the map.size() shows there is only one

map<Key,Key,byKey> firstmap;  
map<Key,Key>::iterator it;
firstmap.insert(pair<Key,Key>(base,stepguess));
firstmap.insert(pair<Key,Key>(stepguess,base));
firstmap[stepguess]=base;
cout << "wait";
cout << "mymap.size() is " << firstmap.size() << '\n';

Upvotes: 0

Views: 82

Answers (2)

Bill Lynch
Bill Lynch

Reputation: 81926

So, here's what I know:

class Key {
    public:
        int keyToInt() const {
            return atoi(digit);
        }

    private:
        char digit[5];
};

You've also suggested, that there is an example Key that has:

Key k;
k.digit = {1, 2, 13, 20, 28};

In this case, you have 2 errors:

  1. digit is not null terminated. So calling atoi() on it is undefined behavior.
  2. The ascii characters in digit are not numbers, so you're going to get unhelpful results.

We can also build up a complete test case that shows that std::map is sane.

#include <map>
#include <cassert>
#include <cstring>

class Key {
    public:
        Key() {
            strncpy(m_digit, "0", 5);
            assert(m_digit[4] == '\0');
        }

        Key(const char *digit) {
            strncpy(m_digit, digit, 5);
            assert(m_digit[4] == '\0');
        }

        int keyToInt() const {
            return atoi(m_digit);
        }

    private:
        char m_digit[5];
};

struct byKey {
    bool operator () ( Key const & key1, Key const & key2) const {
        return key1.keyToInt() < key2.keyToInt();
    }
};

int main() {
    std::map<Key, Key, byKey> myMap;

    Key a("123");
    Key b("234");

    myMap[a] = b;
    myMap[b] = a;

    assert(myMap.size() == 2);
}

Upvotes: 1

fluffy
fluffy

Reputation: 5314

Any time you're converting your key to an integer to compare that way, you're probably better off just comparing the fields directly. In this particular case, consider using memcmp, e.g.:

bool operator()(const Key& lhs, const Key& rhs) {
    return memcmp(lhs.digit, rhs.digit, sizeof(Key::digit)) < 0;
}

atoi in this case will always return 0 unless you have values which are valid ASCII digits (which these are not).

Upvotes: 2

Related Questions