【问题标题】:yaml-cpp to std::vector iteration weird behaviouryaml-cpp 到 std::vector 迭代奇怪的行为
【发布时间】:2019-10-31 18:32:09
【问题描述】:

我在阅读 yaml 文件时发现了一些(在我看来)相当奇怪的东西。也许你们中的一个可以解释一下这两个代码之间的区别。

我尝试读取的 yaml 文件如下所示:

map:
  - [0 0 0 0]
    - 0:
      - 0.123
    - 1:
      - -0.234
  - [0 0 0 1]
    - 0:
      - 0.00
    - 1:
      - 1.234
# and many more vector to int to doubles.

现在我正在尝试将其读入std::map<std::vector<int>, std::map<int, double> >供以后使用。

我尝试使用来自 yaml-cpp 的 STL 转换来做到这一点:

std::map<std::vector<int>, std::map<int, double> > the_map = node.as<std::map<std::vector<int>, std::map<int, double> > >();

但是由于这不起作用(现在没有错误消息,但这并不是问题的真正含义,只是作为解释)我编写了自己的读取例程,如下所示:

YAML::Node node = YAML::LoadFile(name);
for(YAML::const_iterator n = node["map"].begin(); n != node["map"].end(); ++n){
    auto n_0 = (*n).begin();
    for(auto it = n_0->first.as<std::vector<int> >().begin(); it != n_0->first.as<std::vector<int> >().end(); ++it){
        std::cout << *it << " ";
    }
    // Some more stuff
}

它会导致一些奇怪的输出:

937068720 21864 0 0 
937068720 21864 0 1 

但是,如果我将其更改为以下代码:

YAML::Node node = YAML::LoadFile(name);
for(YAML::const_iterator n = node["map"].begin(); n != node["map"].end(); ++n){
    auto n_0 = (*n).begin();
    std::vector<int> vec = n_0->first.as<std::vector<int> >();
    for(auto it = vec.begin(); it != vec.end(); ++it){
        std::cout << *it << " ";
    }
    // Some more stuff
}

一切都如预期:

0 0 0 0
0 0 0 1

两者有什么区别?为什么我必须专门声明向量? 即使在 .begin() 之前的语句周围加上括号也没有什么不同。像这样:

for(auto it = (n_0->first.as<std::vector<int> >()).begin(); it != (n_0->first.as<std::vector<int> >()).end(); ++it)

谁能给我解释一下?第一个和第二个代码有什么区别?

而且由于我是 YAML 新手,我很高兴看到任何关于读取此类文件的改进建议,但是这不是我主要关心的问题。

【问题讨论】:

  • 在第一个版本中,您调用了两次first.as&lt;std::vector&lt;int&gt; &gt;()。每个调用都返回一个不同的向量,因此您通过比较从一个向量获得的迭代器与从不同向量获得的迭代器来执行 UB。第一个版本还从临时向量中获取begin(),并在临时向量被破坏后继续使用它,这是UB的另一个来源。
  • 啊,好吧,这更有意义,但是为什么它会在四个输出之后终止呢?它不应该遇到未定义的行为吗?
  • 恰好在四个输出之后终止是未定义行为的合法表现。

标签: c++ vector stdmap yaml-cpp


【解决方案1】:

您的 YAML 无效!参见,例如,online parser;并且yaml-cpp 同意:使用您的 YAML 运行实用函数util/parse 给出:

yaml-cpp: error at line 3, column 5: end of sequence not found

也许你的意思是这样的:

map:
  [0 0 0 0]:
    - 0:
      - 0.123
    - 1:
      - -0.234
  [0 0 0 1]:
    - 0:
      - 0.00
    - 1:
      - 1.234

这至少是有效的 YAML,但它可能不是您期望的格式。分析如下:

map:           // map of string ->
  [0 0 0 0]:   //  map of vector of int ->
    - 0:       //   vector of map of int to ->
      - 0.123  //    vector of double
    - 1:
      - -0.234
  [0 0 0 1]:
    - 0:
      - 0.00
    - 1:
      - 1.234

在标准库函数中,这是一个

std::map<string, std::map<std::vector<int>, std::vector<std::map<int, std::vector<double>>>>>

【讨论】:

  • 谢谢!由于该文件是由我自己的代码编写的,因此我对其进行了更改以表示正确的结构,因此为map&lt;string, map&lt;int, double&gt; &gt;。也许你可以帮我写一个这样的结构。我尝试将 Emitter 或 force_insert 插入一个节点,但两者都没有达到预期的效果(我在 yaml 文件中得到了很多问号......)。我可以提出一个新问题,如果这样更容易:)
猜你喜欢
  • 2011-03-06
  • 2020-03-10
  • 2016-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
  • 2020-06-15
相关资源
最近更新 更多