迭代C++ std :: map的正确方法不起作用

Ala*_*lan 1 c++ xml stl stdmap abstract-syntax-tree

所以我有一个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;
}
Run Code Online (Sandbox Code Playgroud)

结构正是我想要的方式: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>
Run Code Online (Sandbox Code Playgroud)

此示例还演示了此问题.我用线条迭代所有标签

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

并将它们输出为key ="value".但是,有时这个循环会跳过最后一个元素.请注意紧跟此循环后的行如何输出标记数.当存在两个标签时,实际只显示第一个标签.为什么不显示第二个?

编辑:马克B回答了这个问题; 阅读他的答案,以确切解释出现了什么问题.他从心理上猜测这是getTags()的定义:

std::map<std::string,std::string> getTags()
{   
    return tags;
};
Run Code Online (Sandbox Code Playgroud)

将其更改为此(添加&符号)就可以了:

std::map<std::string,std::string> & getTags()
{   
    return tags;
};
Run Code Online (Sandbox Code Playgroud)

Mar*_*k B 6

我将使用我的通灵调试技巧并建议getTags()按值返回容器(而不是对实际容器的引用),因此beginend节点引用不同的临时容器.在那时,无论迭代发生了什么,都是合理的游戏,因为最初的临时容器已经消失.