此行无法正常工作:
for (auto prod : productions_[*productionNonterm])
productions_[nonterminal].push_back(prod);
如果productions _ [* productionNonterm]只有1个元素,那么一切都很好。但是,如果它至少包含2个元素,则会修改productionNonterm,我也不知道为什么。
vector<string> nonterminals_;
unordered_map<string, vector<string>> productions_;
for (const auto &nonterminal : nonterminals_) {
for (auto productionNonterm = productions_[nonterminal].begin(); productionNonterm != productions_[nonterminal].end(); ++productionNonterm) {
if (cntNonterminalsInProduction(*productionNonterm) == 1 && cntTerminalsInProduction(*productionNonterm) == 0) {
nonterminals_.erase(find(nonterminals_.begin(), nonterminals_.end(), *productionNonterm));
for (auto prod : productions_[*productionNonterm])
productions_[nonterminal].push_back(prod);
productions_[*productionNonterm].erase(productions_[*productionNonterm].begin(), productions_[*productionNonterm].end());
productions_[nonterminal].erase(productionNonterm);
--productionNonterm;
}
}
}
答案 0 :(得分:1)
迭代器productionNonterm
的问题,它在循环过程中变得无效:
一旦开始循环
for (auto prod : productions_[*productionNonterm])
productions_[nonterminal].push_back(prod);
您将使用指向productionNonterm
中一个(第一个)元素的有效迭代器(productions_[nonterminal]
)。
但是在第一次执行循环的主体之后-向量productions_[nonterminal]
将重新分配其元素(由于增长),并且指针(迭代器)将无效...
答案 1 :(得分:0)
在迭代时修改集合很棘手,通常不值得在容器中支持它的开销。在这种情况下(向量),一旦向量在增长时重新分配,就使迭代器(即指向向量存储的指针)失效。
看看vector::push_back,尤其是关于迭代器有效性的讨论。
在实践中,可以通过调整向量的大小来避免出现此特定问题,但是在跟踪相对于迭代器放置新元素的位置等方面也存在一些问题。通常,即使在以下情况下,它也会导致难以遵循的代码这是正确的(或更糟的是,看上去却有细微的问题)。
我建议您重写为两遍方法,收集一次添加或删除的元素,然后删除它们,等等。除非您有非常好的(并且经过测量!)性能理由不这样做,否则以便于理解和维护。回想一下vector :: erase可以取一个范围。
这也值得问:这里的顺序重要吗?如果您使用的是std :: unordered_set,在这种情况下您就不会遇到这个特殊的问题。
在“修复”此方法之前,先了解一下您对该方法的看法。