2013-08-22 3 views
3

Я написал функцию сравнения для std :: map, чтобы у меня были пользовательские типы ключей.std :: map compare function и NULL

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, но кажется, что что-то не так, и я не хочу вылечить симптом, а не проблему.

Благодаря

+0

Показать, где вы добавляете элементы. – imreal

+1

Не могли бы вы разместить какой-то код о том, как вы используете это, и/или как вы добавляете элементы на карту? Я мог бы попытаться воспроизвести проблему. Я не вижу никаких очевидных проблем с этим кодом, поэтому, возможно, это что-то странное в реализации. –

+0

Если вы GGString входите в 'NULL' свою вставку' NULL' * ключ *, который вы ищете, а не значение «NULL' * * –

ответ

4

В этом коде:

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); 
} 

Надеется, что это помогает!

+0

Добавление этого кода не устраняет проблему, все еще происходит сбой в одном месте. –

+1

Можете ли вы опубликовать трассировку стека? Где ошибка? – templatetypedef

+0

След стека добавлен. –

0

Интересно, если ключ функция сравнения должна быть пересмотрена, чтобы что-то вроде этого:

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

В основном я думаю, что параметры должны быть константными ссылками, а также о том, что функция должна защищать от разыменования NULL указатели

+0

Делает сравнение медленнее и, вероятно, лечит симптом. – ypnos

+1

Поддержка «null» может быть хорошей идеей, но эта функция не дает строгого слабого порядка. Для любого значения 'a',' comp (a, null) 'и' comp (null, a) 'оба являются ложными, что означает, что все значения эквивалентны« null », и поэтому все значения эквивалентны друг другу. –

+0

Вместо этого сделайте следующее: 'if (rhs == NULL) return false; if (lhs == NULL) return true; ' –

0

Вы уверены, что произошел сбой при доступе к 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 
+0

Да, это указатель NULL, а не указатель мусора. –