【问题标题】:c++ map iterator doesn't start from the first itemc ++ map迭代器不从第一项开始
【发布时间】:2017-12-20 02:58:49
【问题描述】:

由于某种原因,我正在尝试迭代地图,迭代器没有从第一项开始。

const Noeud* origine = &noeuds.at(nomorigine);
map<string, Noeud>::iterator it;
origine->seeRoutes(); //Prints n5: n4 n6
it = origine->getRoutes().begin();
cout<<it->first<<endl; //Prints n4.
for(it = origine->getRoutes().begin(); it != origine->getRoutes().end(); it++){
    cout<<it->first<<endl; //Prints n6.
}

void Noeud::seeRoutes() const{
    cout<<getNom()<<": ";
    for(auto it = routes.begin(); it != routes.end(); it++){
        cout<<it->first<<" ";
    }
    cout<<endl;
}

我尝试过使用auto,但结果是一样的。这个问题的原因可能是什么?

这是 Noeud 的类:

class Noeud{
  public:
    string getNom() const;
    void setNom(const string& nom);
    void ajouterRoute(const string& nomRoute, const Noeud noeud);
    map<string, Noeud> getRoutes() const;
    void seeRoutes() const;

  private:
    string nom;
    map<string, Noeud> routes;
};

【问题讨论】:

  • 为什么不在for循环中使用++it?
  • 类似的错误和答案为here
  • @Davar 我认为 ++it 和 it++ 之间没有区别。在 for 循环中预增量总是更好吗?
  • @AnthonyGauthier ++it 运算符采用it,递增it,然后返回itit++ 获取it,复制it,递增it,然后返回副本。在迭代器for循环中没关系,因为您正在查看it,没有考虑到它返回了一些副本,但它仍然创建了一个副本(我不确定自动优化是否能够抓住这个。)。您可以尝试一个示例:int main() { int x = 0; int y = 0; std::cout &lt;&lt; x++ &lt;&lt; " " &lt;&lt; ++y; }en.cppreference.com/w/cpp/language/operator_incdec

标签: c++ dictionary iterator


【解决方案1】:

getRoutes() 按值返回,这意味着origine-&gt;getRoutes() 返回的是一个temporary,它将在完整表达式后被销毁。在那之后it 变得悬空,任何对它的取消引用都会导致UB

您可以使用命名变量来避免这个问题。例如

map<string, Noeud> m = origine->getRoutes();
it = m.begin();
...

请注意,出于同样的原因,在 for 循环中 origine-&gt;getRoutes() 被调用两次并返回两个不相关的对象。从它们那里得到的迭代器是不兼容的,比较它们是不正确的。

【讨论】:

  • 它有效,谢谢。那么避免这个问题的唯一方法是在循环之前将映射存储在命名变量中?
  • @AnthonyGauthier 根据设计,将 getRoutes 更改为按引用返回也可以解决问题。确保返回一个有效的参考。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多