我正在使用C ++上的迭代器,我在这里遇到了一些麻烦。它在行interIterator ++上的表达式(this-> _Has_container())上说“Debug Assertion Failed”。 距离列表是矢量<矢量< DistanceNode>取代。我做错了什么?
vector< vector<DistanceNode> >::iterator externIterator = distanceList.begin();
while (externIterator != distanceList.end()) {
vector<DistanceNode>::iterator interIterator = externIterator->begin();
while (interIterator != externIterator->end()){
if (interIterator->getReference() == tmp){
//remove element pointed by interIterator
externIterator->erase(interIterator);
} // if
interIterator++;
} // while
externIterator++;
} // while
答案 0 :(得分:13)
vector erase()
向下一个元素返回一个新的迭代器。擦除元素和之后的元素的所有迭代器都将失效。但是,您的循环忽略了这一点,并继续使用interIterator
。
您的代码应如下所示:
if (condition)
interIterator = externIterator->erase(interIterator);
else
++interIterator; // (generally better practice to use pre-increment)
答案 1 :(得分:5)
在迭代它时,你不能从序列容器中删除元素 - 至少不是你这样做的方式 - 因为调用erase
使迭代器无效。您应该将erase
的返回值赋给迭代器并抑制增量:
while (interIterator != externIterator->end()){
if (interIterator->getReference() == tmp){
interIterator = externIterator->erase(interIterator);
} else {
++interIterator;
}
}
此外,在预增量(++ i)执行时,永远不要使用后增量(i ++)。
答案 2 :(得分:1)
我将冒昧地重写代码:
class ByReference: public std::unary_function<bool, DistanceNode>
{
public:
explicit ByReference(const Reference& r): mReference(r) {}
bool operator()(const DistanceNode& node) const
{
return node.getReference() == r;
}
private:
Reference mReference;
};
typedef std::vector< std::vector< DistanceNode > >::iterator iterator_t;
for (iterator_t it = dl.begin(), end = dl.end(); it != end; ++it)
{
it->erase(
std::remove_if(it->begin(), it->end(), ByReference(tmp)),
it->end()
);
}
为什么?
externIterator
)遍历整个范围的元素,而不会修改范围本身,这是for
的用途,这样你就不会忘记增加(不可否认的是for_each
会更好,但语法可能很尴尬)erase
时,你实际上正在切割你所坐的分支,这需要跳转(使用返回的值)。在这种情况下,您要完成的操作(根据特定条件清除列表)正是为remove-erase
惯用法定制的。请注意,如果我们拥有真正的lambda支持,可以整理代码。在C ++ 0x中,我们会写:
std::for_each(distanceList.begin(), distanceList.end(),
[const& tmp](std::vector<DistanceNode>& vec)
{
vec.erase(
std::remove_if(vec.begin(), vec.end(),
[const& tmp](const DistanceNode& dn) { return dn.getReference() == tmp; }
),
vec.end()
);
}
);
正如您所看到的,我们看不到任何迭代器递增/解除引用,它们全部包含在专用算法中,以确保一切都得到妥善处理。
我会告诉你语法看起来很奇怪,但我想这是因为我们还没有习惯它。