【问题标题】:Stop on last element iterators C++在最后一个元素迭代器上停止 C++
【发布时间】:2012-06-17 18:40:54
【问题描述】:

在倒数第二个元素之后执行循环和停止的最优雅的方法是什么(在 C++11 中)?

注意:我的意思是双向迭代器;当然,随机访问迭代器是一个微不足道的特例,因为它们有 +- 运算符。

std::list<double> x{1,2,3,4,5,6};

for (auto iter = x.begin(); iter != x.end(); ++iter) {
  auto iter2 = iter;
  ++iter2;
  if (iter2 == x.end()) break;
  std::cout << *iter << std::endl;
}

【问题讨论】:

  • 你确定你的意思不是“前向迭代器”而不是“双向迭代器”吗?双向情况似乎也很简单。
  • @LucTouraille std::list 提供了双向迭代器,所以这对我来说很好——你能展示你正在考虑的简单解决方案吗?
  • 如果while (iter != x.end() - 1) 对你来说是微不足道的,那么while (iter != --x.end()) 也应该很简单,不是吗?

标签: c++ iterator c++11


【解决方案1】:

使用std::prev函数:

std::list<double> x{1,2,3,4,5,6};

for (auto iter = x.begin(); iter != std::prev(x.end()); ++iter) {
  std::cout << *iter << std::endl;
}

【讨论】:

  • 我不能说我在这里看到了关于std::prev 的任何特别引人注目的地方。打字越多越好? ;-]
  • @ildjarn 好吧,我对“倒数第二个元素”有点困惑,并认为它会是 std::prev(x.end(), 2) :S
  • @MarkRansom 实际上,我的目标是成对地遍历相邻的项目(例如,对项目列表执行有限差分:fd[i] = a[i+1] - a[i]),所以我认为最好的解决方案是从iter = std::next(x.begin()) 开始并在x.end() 停止。然后,在循环内部,我将查看*iter - *std::prev(iter)。这对于包含 0 或 1 个元素的列表应该是安全的。
【解决方案2】:

在 C++03 中应该是:

for (std::list<double>::iterator it = x.begin(), it_last = --x.end();
     it != it_last; ++it)
{
    std::cout << *it << '\n';
}

在 C++11 中,根本没有什么不同,只是不那么冗长..:

for (auto it = begin(x), it_last = --end(x); it != it_last; ++it)
{
    std::cout << *it << '\n';
}

【讨论】:

  • x.end()-- 应该是--x.end()
  • @Luc :是的,我在想--end(x) 通常不适用于迭代器(即如果迭代器实际上只是一个指针),但后来我意识到end(x)-- 不会也不是。 :-P
  • 在实践中,这可能比 R. Martinho 的答案更打字,因为这适用于任何双向迭代器,而这不是。因此,如果在采用迭代器的算法中使用,则通常需要对指针进行专门化/重载或对随机访问迭代器进行标签调度。但是,如果 std::list 旨在成为整个问题,而不仅仅是一个示例,那么就可以了。
  • @Steve :除了指针之外,这也适用于任何双向迭代器。还是我遗漏了一些明显的东西?
  • 我不认为你错过了什么,这正是我所说的。它不适用于指针,而std::prev 确实适用,这意味着在您想要一个适用于任何双向迭代器的解决方案的情况下,这需要更多的输入。我简要描述了额外的输入是什么,以防有人试图使用这个答案:-)
【解决方案3】:

对 R. Martinho Fernandes 的回答略有改进:

使用std::prev函数:

std::list<double> x{1,2,3,4,5,6};

for (auto iter = x.begin(), end=std::prev(x.end()); iter != end; ++iter) {
  std::cout << *iter << std::endl;
}

这只会计算:std::prev(x.end()) 一次。

【讨论】:

  • 说实话,我什至没有想到这个改进。如果我要改进那个代码,我会直接去for(auto&amp;&amp; x : drop_last(x)):相同的性能特征,没有可读性损失(相反)。
  • 有谁知道编译器优化是否会提高性能(即-O3 w/ gcc)?
  • @R.MartinhoFernandes +1 for drop_last,尽管我的应用程序在此处的范围循环中使用std::prev(...) 更好(在每个循环迭代中我需要使用*iter 和(我猜是)*std::next(iter))。
  • 不,基于范围的循环没有迭代器。 x 是对值的引用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-20
  • 2011-02-10
  • 1970-01-01
相关资源
最近更新 更多