end()迭代器上的算术运算

Arithmetic on end() iterator

本文关键字:算术运算 迭代器 end      更新时间:2023-10-16

设A为std::vector<double>

这是否定义明确?

if(!A.empty())
    std::vector<double>::iterator myBack = A.end() - 1;

end迭代器是否只适用于等式和不等式检查?或者,只要我留在容器中,我就可以执行一些指针运算?

在我的平台上,此代码有效。我想知道这是不是便携的。

它是完全有效的,因为vector::iterator是一个随机访问迭代器。您可以对它执行算术运算,而且它不依赖于平台。

std::vector<double>::iterator it = A.end();
while (it != A.begin()){
    --it; //this will skip A.end() and loop will break after processing A.front()
    //do something with 'it'
}

A.end()是指理论上的超越末端元素,因此它不指向元素,因此不应被取消引用。因此,最佳实践是使用反向迭代器,而不是递减结束迭代器。

for(std::vector<double>::reverse_iterator it = A.rbegin(); it != A.rend(); ++it) {
    //do something with 'it'
}

这两个循环做同样的事情,第二个是可以理解的,更干净的方法

如果您注意一些特殊情况,几乎是安全的:

A.end()为您提供了一个迭代器,用于表示std::vector末尾之外的位置。您应该不要尝试取消引用它。

如果向量有零个元素,那么A.end() - 1而不是定义良好的。在所有其他情况下,只要在容器边界内,就可以执行指针运算。请注意,该标准保证std::vector数据是连续的,并且以与contains类型的C++数组完全相同的方式进行打包。唯一的例外是std::vector<bool>,由于标准规定的紧密包装专业化,其表现有所不同。(请注意,sizeof(bool),而不是标准保证具有特定值)。

如果我是你,我会使用A.rbegin()访问最右边的元素并检查返回值,然后继续并坚持迭代器公式。很容易忘记std::vector<bool>的专业化。

我意识到这个问题有点老了,但我在这里是针对end() - 1的,我发现现有的答案和评论信息丰富且合理,但由于缺乏引用,无法令人信服,而且我也不确定它们是否针对vector。因此,我挖掘了尽可能多的具体信息,以说服自己这里的答案是正确的。

这篇文章代表了我为确认答案所做的研究,基本上是我的笔记,但我试图让它尽可能连贯,我认为它可能有用。如果这里有任何问题,我们将非常感谢您的更正。


重述答案

TL;DR这里是肯定的,这里的答案是正确的,不仅适用于vector,而且适用于更一般的情况:

如果容器的迭代器类型满足双向迭代器(因此提供递减操作),则以下内容对于任何容器类型始终有效,其中e初始化为container.end()的返回值:

  • 如果!container.empty(),则--e是有效的
  • 如果!container.empty(),则++(--e) == container.end()为真

如果迭代器也满足RandomAccessIterator,那么这些更通用的语句是有效的:

  • [0,container.size()]中任何整数ne - ne -= n
  • [-container.size()中任意整数ne + ne += n,0]

因此,OP中的vector示例不仅很好,正如其他答案所指出的那样,而且它定义良好,并保证对任何容器类型都很好。


推理

所以现在我觉得少了一点。首先,从容器要求:

复杂性
表达式返回类型语义条件
a.end()(const_)迭代器迭代器到a的最后一个元素后的一个常量