std::map функция за сравнение и NULL

Написах функция за сравнение за std::map, за да мога да имам потребителски типове ключове.

std::map<GGString *, GGObject *, GGDictionaryMapCompare> _map;

...

class GGDictionaryMapCompare
{
public:
    bool operator()(GGString * lhs, GGString * rhs)
    {
        return strcmp(lhs->str(), rhs->str()) < 0;
    }
};

Код, който добавя елементи:

GGObject *GGDictionary::addKeyObject(GGString *theKey, GGObject *theObject)
{
    if (theKey == NULL || theObject == NULL)
        return NULL;

    _map.insert(std::pair<GGString *, GGObject *>(theKey, theObject));

    return theObject;
}

Код, който причинява срива:

GGObject *GGDictionary::objectForKey(GGString *theKey)
{
    if (theKey == NULL)
        return NULL;

    std::map<GGString *, GGObject *, GGDictionaryMapCompare>::iterator ii = _map.find(theKey);
    if (ii == _map.end())
    return NULL;

    return GGAutoRelease(ii->second);
}

Проследяване на стека:

#0  0x00009f15 in GGString::str()
#1  0x0004a4c4 in GGDictionaryMapCompare::operator()(GGString*, GGString*)
#2  0x0004a3d3 in std::_Rb_tree<GGString*, std::pair<GGString* const, GGObject*>, std::_Select1st<std::pair<GGString* const, GGObject*> >, GGDictionaryMapCompare, std::allocator<std::pair<GGString* const, GGObject*> > >::find(GGString* const&)
#3  0x00049b04 in std::map<GGString*, GGObject*, GGDictionaryMapCompare, std::allocator<std::pair<GGString* const, GGObject*> > >::find(GGString* const&)
#4  0x00048ec9 in GGDictionary::objectForKey(GGString*)

Проблемът е, че lhs идва в NULL. Никога не вмъквам NULL в картата, така че това не трябва да се случва. Някаква идея защо? Или просто правя функцията за сравнение погрешно? Мога да предпазя срещу получаване на NULL, но изглежда, че нещо не е наред и не искам да лекувам симптом, а не проблема.

Благодаря


person Roger Gilbrat    schedule 22.08.2013    source източник
comment
Покажете къде добавяте елементи.   -  person imreal    schedule 23.08.2013
comment
Бихте ли публикували код за това как използвате това и/или как добавяте елементи към картата? Мога да опитам да възпроизведа проблема. Не виждам никакви очевидни проблеми с този код, така че може би е нещо странно в изпълнението.   -  person Michael Oliver    schedule 23.08.2013
comment
Ако GGString идва NULL, това е вмъкването на NULL ключ, който търсите, НЕ NULL стойност   -  person Mike Vine    schedule 23.08.2013
comment
Добавих нов код, но вмъкването на NULL ключове или стойности е защитено срещу. Това е единствената функция, която вмъква ключове/стойности.   -  person Roger Gilbrat    schedule 23.08.2013
comment
Не проверявате аргумента theKey за NULL. map::find ще използва вашия компаратор.   -  person dhavenith    schedule 23.08.2013
comment
Току-що добавен код за проверка дали ключът е NULL и това не решава проблема, все още се срива на същото място.   -  person Roger Gilbrat    schedule 23.08.2013
comment
Какво прави GGAutoRelease?   -  person user2093113    schedule 23.08.2013
comment
Сигурни ли сте, че показалецът наистина е NULL, а не просто невалиден?   -  person Mark Ransom    schedule 23.08.2013
comment
Сигурни ли сте, че не променяте _map никъде другаде, напр. с неволно _map[foo], където foo е NULL?   -  person Nate Kohl    schedule 23.08.2013
comment
Да, проверявам целия си код, добавям, че има само това едно място.   -  person Roger Gilbrat    schedule 23.08.2013
comment
GGString * обикновено е знак за лош дизайн. Има много малко случаи, в които е полезно да се прави разлика между празен контейнер и никакъв контейнер. Като странична полза, std::map<GGString, GGObject *> няма да има тези проблеми.   -  person MSalters    schedule 23.08.2013


Отговори (3)


В този код:

GGObject *GGDictionary::objectForKey(GGString *theKey)
{
    std::map<GGString *, GGObject *, GGDictionaryMapCompare>::iterator ii = _map.find(theKey);
    if (ii == _map.end())
        return NULL;

    return GGAutoRelease(ii->second);
}

Вие не проверявате дали theKey е NULL. Съответно, когато компараторът се извика на theKey и всеки елемент от map, вие ще дереферирате NULL.

За да коригирате това, опитайте да добавите проверка NULL:

GGObject *GGDictionary::objectForKey(GGString *theKey)
{
    if (theKey == NULL) return NULL;

    std::map<GGString *, GGObject *, GGDictionaryMapCompare>::iterator ii = _map.find(theKey);
    if (ii == _map.end())
        return NULL;

    return GGAutoRelease(ii->second);
}

Надявам се това да помогне!

person templatetypedef    schedule 22.08.2013
comment
Добавянето на този код не решава проблема, все още се срива на същото място. - person Roger Gilbrat; 23.08.2013
comment
@RogerGilbrat- Сигурен ли си, че предаваш NULL указател, а не боклук? Можете ли да ни кажете какъв е лошият показалец? - person templatetypedef; 23.08.2013

Чудя се дали функцията за сравняване на ключове трябва да бъде преработена на нещо подобно:

bool operator()(const GGString *&lhs, const GGString *&rhs)
{
    if (lhs == NULL || rhs == NULL)
    {
       return false;
    }
    return strcmp(lhs->str(), rhs->str()) < 0;
}

По принцип мисля, че параметрите трябва да бъдат константни препратки и също така, че функцията трябва да защитава срещу дерефериране на NULL указатели

person MorbidFuzzball    schedule 22.08.2013
comment
Това прави сравненията по-бавни и вероятно лекува симптома. - person ypnos; 23.08.2013
comment
Поддържането на null може да е добра идея, но тази функция не дава строго слабо подреждане. За всяка стойност a, comp(a, null) и comp(null, a) са неверни, което означава, че всички стойности са еквивалентни на null и следователно всички стойности са еквивалентни една на друга. - person Derek Ledbetter; 23.08.2013
comment
Вместо това направете следното: if (rhs == NULL) return false; if (lhs == NULL) return true; - person Derek Ledbetter; 23.08.2013

Сигурни ли сте, че сривът се случва при достъп до NULL? Вие съхранявате указатели в картата; възможно ли е да сте изтрили един от указателите, след като сте го съхранили в картата? Нещо като това:

dict->addKeyObject( key1, obj1 );
delete key1; // now dict has a pointer to deleted key1
dict->addKeyObject( key2, obj2 ); // now dict will compare key2 to key1, causing crash
person Michael    schedule 22.08.2013