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

时间:2013-01-30 14:08:23

标签: 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;
}

结构正是我想要的方式: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 << "\" ";
    }

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

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

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

将其更改为此(添加&符号)可以解决问题:

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

2 个答案:

答案 0 :(得分:6)

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

答案 1 :(得分:0)

马克可能是对的。

另一种可能性是你破坏了这张地图。通过在地图中编辑密钥来说。