xml — правильный способ перебора C ++ std :: map не работает

Итак, у меня есть абстрактное синтаксическое дерево объектов Node. Каждый узел имеет любое количество дочерних узлов, а также любое количество тегов, которые являются кусочками информации, которые присоединяются к узлу через структуру std :: map. Теперь я хочу напечатать все синтаксическое дерево в XML-подобном формате. Для этого я использую эту функцию:

int __ostreamNode_indent = 0;
std::ostream & operator << ( std::ostream & ss, Node* n )
{
for( int i = 0 ; i < __ostreamNode_indent ; ++i )
ss << "  ";

ss << "<" << n->getSymbolType() << " ";
for( std::map<std::string,std::string>::iterator itr = n->getTags().begin() ; itr != n->getTags().end() ; ++itr )
{
ss << itr->first << "=\"" << itr->second << "\" ";
}
ss << "numtags=" << n->getTags().size() << " ";

if( n->getChildren().size() == 0 )
ss << "/";

ss << ">" << std::endl;

__ostreamNode_indent++;
for( unsigned int i = 0 ; i != n->getChildren().size() ; ++i )
{
ss <<  n->getChildren().at(i);
}
__ostreamNode_indent--;

if( n->getChildren().size() != 0 )
{
for( int i = 0 ; i < __ostreamNode_indent ; ++i )
ss << "  ";

ss << "</" << n->getSymbolType() << ">" << std::endl;
}

return ss;
}

Структура — это именно то, что мне нужно: тип XML-тега — это тип узла, а теги узла встроены в один и тот же открывающий тег XML. Дочерние узлы размещаются между открывающим и закрывающим тегами. Вот пример:

<block line="0" numtags=2 >
<funcdef line="0" numtags=2 >
<identifier line="0" col="13" value="main" numtags=3 />
<expressionunion line="0" numtags=2 >
<identifier line="0" col="16" value="a" numtags=3 />
<identifier line="0" col="19" value="b" numtags=3 />
</expressionunion>
<assignment line="1" numtags=2 >
<identifier line="1" col="5" value="c" numtags=3 />
<numel line="1" numtags=2 >
<solveunder line="1" numtags=2 >
<identifier line="1" col="11" value="a" numtags=3 />
<identifier line="1" col="16" value="b" numtags=3 />
</solveunder>
</numel>
</assignment>
<return line="2" numtags=2 >
<power line="2" numtags=2 >
<identifier line="2" col="12" value="c" numtags=3 />
<identifier line="2" col="14" value="b" numtags=3 />
</power>
</return>
</funcdef>
</block>

Этот пример также демонстрирует проблему. Я перебираю все теги со строками

    for( std::map<std::string,std::string>::iterator itr = n->getTags().begin() ; itr != n->getTags().end() ; ++itr )
{
ss << itr->first << "=\"" << itr->second << "\" ";
}

и выведите их как ключ = «значение». Однако иногда этот цикл пропускает последний элемент. Обратите внимание, как строка, следующая непосредственно за этим циклом, выводит количество тегов. Когда присутствуют два тега, на самом деле отображается только первый. Почему не показывается второй?

РЕДАКТИРОВАТЬ: Марк B ответил на вопрос; прочитайте его ответ для точного объяснения того, что пошло не так. Он психически предположил, что это было определение getTags ():

std::map<std::string,std::string> getTags()
{
return tags;
};

Изменение этого (добавление амперсанда) сделало трюк:

std::map<std::string,std::string> & getTags()
{
return tags;
};

1

Решение

Я собираюсь использовать свои навыки психической отладки и предположить, что getTags() возвращает контейнер по значению (а не ссылку на фактический контейнер), поэтому begin а также end узлы ссылаются на разные временные контейнеры. В этот момент все, что происходит с итерацией, является честной игрой, поскольку первоначальный временный контейнер исчез.

6

Другие решения

Марк, наверное, прав.

Другая возможность — вы испортили эту карту. Скажите, редактируя ключ после того, как он находится на карте.

0