【问题标题】:*iterator causes segfault*iterator 导致段错误
【发布时间】:2011-04-03 09:50:00
【问题描述】:

我正在尝试浏览列表。以下是一些声明:

list<CG1_Edge*> ActiveEdges;
list<CG1_Edge*>::iterator ActiveEdgeIterator;

有时,此代码在第 2 行出现段错误:

for (this->ActiveEdgeIterator = this->ActiveEdges.begin(); this->ActiveEdgeIterator != this->ActiveEdges.end(); ++this->ActiveEdgeIterator) {
    CG1_Edge* currentEdge = *this->ActiveEdgeIterator;
    if (currentEdge->y_up < y)
        this->ActiveEdges.erase(this->ActiveEdgeIterator);
}

这可能导致段错误的常见原因有哪些?

【问题讨论】:

  • 只是风格说明:我会用std::remove_if 替换for 循环并调整容器大小。来自 STL 的算法隐藏了许多迭代器细节并使代码更具可读性(当我看到 for 循环时,我只知道这是某种迭代,而当我看到 STL 算法时,我确切地知道它是什么)。跨度>
  • Begemoth 的评论应该是公认的答案。根据标准擦除使“所有迭代器和对位置后元素的引用”无效。所以你至少 需要使用rbegin() 和rend()。但是为什么不使用 std::alogirthms!
  • @sehe:不,这是不正确的。 list::erase 不会使迭代器无效,除了那些位于已擦除元素处的迭代器。
  • 我的错,我错误地引用了 std::vector 的文档

标签: c++ oop iterator c++-standard-library


【解决方案1】:

你应该使用类似的东西:

for (this->ActiveEdgeIterator = this->ActiveEdges.begin(); this->ActiveEdgeIterator != this->ActiveEdges.end(); ) {
    CG1_Edge* currentEdge = *this->ActiveEdgeIterator;
    if (currentEdge->y_up < y)
        this->ActiveEdgeIterator = this->ActiveEdges.erase(this->ActiveEdgeIterator);
    else
        ++this->ActiveEdgeIterator;
}

因为erase返回一个定位在下一个元素的迭代器。

(注意:将迭代器作为成员看起来很奇怪。)

【讨论】:

  • 是的,这个 sn-p 与 Alexander 的不同,它不会让您在每次擦除一个元素时跳过一个元素,并且不会在您擦除最后一个元素时使迭代器超出范围。
  • 由于这显然没有那么大的缺陷,我决定放弃我的回应,转而支持你的回应:-)
【解决方案2】:

Begemoth 的评论应该是公认的答案。 根据标准擦除使“位置后的所有迭代器和对元素的引用”无效我的错误;这是针对矢量和可能的其他容器;所以至少为了避免意外,您应该做好改用算法版本)。

所以你已经使用 rbegin() 和 rend() 会更安全。但是为什么不使用 std::alogirthms!

struct Predicate 
{
     int _y;
     explicit Predicate(int y) : _y(y) {}

     bool operator()(const CG1_Edge edge) const
     {
          return currentEdge->y_up < _y;
     }
};

std::erase(
     std::remove_if(this->ActiveEdges.begin(), this->ActiveEdges.end(), Predicate(y)),
     this->ActiveEdges.end());

【讨论】:

  • list::erasevector::erase 是不同的野兽。 list::erase 仅使位于已擦除元素处的迭代器无效。不是之后的,不是之前的。
  • 存在时首选成员函数。它们可能针对相关容器类型进行了优化。 list::remove_if 在这种情况下更好。
  • ... 因为它实际上删除了元素,而不是像 std::remove_if 那样将它们移动到容器的后面。所以不需要擦除。
  • 是的。都是真的。我喜欢坚持使用算法,因为从 list 切换到 vector 不会有任何意外。但是:意识胜过惯例并在必要时进行优化!
猜你喜欢
  • 1970-01-01
  • 2011-02-25
  • 2015-09-03
  • 2012-08-17
  • 1970-01-01
  • 2011-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多