Странная ошибка при вставке в С++ std::map

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

(*foo)[index] = bar;

Позже, когда я пытаюсь выполнить итерацию по коллекции, мне возвращаются пары ключ/значение, которые содержат null для атрибута значения во всех случаях, кроме первого элемента (map.begin()). Странно то, что если я делаю вставку через функцию вставки карты, все хорошо, т.е.:

foo->insert(std::pair<KeyType,ValueType>(myKey, myValue));

С чего бы это? Разве эти два метода функционально не эквивалентны? Я вставил несколько фрагментов фактического кода ниже для контекста

...
typedef std::map<int, SCNode*> SCNodeMap;
...


void StemAndCycle::getCycleNodes(SCNodeMap* cycleNodes)
{
    (*cycleNodes)[root->getId()] = root;

    SCNode* tmp = root->getSucc();
    while(tmp->getId() != root->getId())
    {
        // (*cycleNodes)[tmp->getId()] == tmp; // crashes (in loop below)
        cycleNodes->insert(std::pair<int, SCNode*>(tmp->getId(), tmp));//OK
        std::pair<int, SCNode*> it = *(cycleNodes->find(tmp->getId()));
        tmp = tmp->getSucc();
    }

    // debugging; print ids of all the SCNode objects in the collection
    std::map<int, SCNode*>::iterator it = cycleNodes->begin();
    while(it != cycleNodes->end())
    {
        std::pair<int, SCNode*> p = (*it);
        SCNode* tmp = (*it).second; // null except for it = cycleNodes->begin()
        std::cout << "tmp node id: "<<tmp->getId()<<std::endl; 
        it++;
    }

}

У меня закончились идеи. У кого-нибудь есть предложение, пожалуйста?


person Daniel    schedule 27.04.2009    source источник


Ответы (3)


В вашем реальном коде у вас есть:

(*cycleNodes)[tmp->getId()] == tmp;

Это не назначит tmp карте, а вместо этого будет ссылаться на карту, создавая пустое значение (см. @Neil Butterworth) — у вас есть == вместо =. Что вы хотите:

(*cycleNodes)[tmp->getId()] = tmp;
person Simon Steele    schedule 27.04.2009
comment
Я знал о другом поведении оператора[], но не могу поверить, что пропустил использование == вместо =! Спасибо Саймон. - person Daniel; 27.04.2009
comment
Спасибо также всем остальным за ваш вклад. - person Daniel; 27.04.2009
comment
Не могу сосчитать, сколько раз я совершал одну и ту же ошибку — обычно ее легче заметить! - person Simon Steele; 28.04.2009

Вы должны знать, что operator[] для std::map вставит значение в карту, если оно не существует, при использовании в таких выражениях:

if ( amap[x] == 42 ) {
   ...
}

Если значение x не существует, оно будет создано и ему будет присвоено значение, созданное конструктором типов значений по умолчанию, или ноль для встроенных типов. Это почти никогда не то, что вам нужно, и вам обычно следует избегать использования operator[] с картами.

person Community    schedule 27.04.2009
comment
Спасибо! Я только что потерял полдня на этот кусок идиотизма. - person Reuben Scratton; 10.06.2013

Есть ли в вашем типе значения оператор присваивания?

Взгляните на эту ссылку. Оператор [] возвращает неконстантную ссылку на значение. Если ваше назначение неверно или каким-то образом работает неожиданным образом, это может быть причиной.

С другой стороны, метод вставки принимает значение и вставляет его в карту. Оператор [] создает объект с помощью конструктора по умолчанию, а затем позволяет вам назначать ему что-то, используя его оператор присваивания.

person Skurmedel    schedule 27.04.2009