设A为std::vector<double>
,
这个定义明确吗?
if(!A.empty())
std::vector<double>::iterator myBack = A.end() - 1;
end
迭代器是否仅适用于均等和不等式检查?或者只要我留在容器中,我就可以执行一些指针运算?
在我的平台上,此代码有效。我想知道这是否便携。
答案 0 :(得分:5)
完全有效,因为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'
}
这两个循环做同样的事情,第二个是可以理解的,更清洁的方法。
答案 1 :(得分:4)
如果您注意到一些特殊情况,那么几乎安全:
A.end()
为您提供一个迭代器,表示std::vector
末尾的位置。您应该不尝试取消引用它。
如果向量的元素为零,则A.end() - 1
不定义良好。在所有其他情况下,只要您处于容器边界内,您就可以执行指针运算。请注意,该标准保证std::vector
数据是连续的并且以与包含类型的C ++数组完全相同的方式打包。唯一的例外是std::vector<bool>
,由于标准规定的紧密包装专业化,其行为有所不同。 (请注意,sizeof(bool)
不保证标准具有特定值。
如果我是你,我会使用A.rbegin()
来访问最右边的元素,并在继续之前检查返回值并坚持迭代器公式。忘记std::vector<bool>
专业化很容易。
答案 2 :(得分:2)
我意识到这个问题有点老了,但我被引导到这里是关于 end() - 1
,我发现现有的答案和评论内容丰富且合理,但由于缺乏引文而无法令人信服,而且我也不是确定它们是否特定于 vector
。所以我尽可能多地挖掘具体信息,让自己相信这里的答案是正确的。
这篇文章代表了我为确认答案所做的研究,基本上是我的笔记,但我试图让它尽可能连贯,我认为它可能会有用。如果这里有任何问题,我们将非常感谢您的更正。
这里的 TL;DR 是的,这里的答案是正确的,不仅适用于 vector
,而且适用于更一般的情况:
如果容器的迭代器类型满足 BidirectionalIterator(因此提供递减操作),那么以下内容将始终有效,对于任何容器类型,其中 e
被初始化到 container.end()
的返回值:
!container.empty()
则 --e
有效。!container.empty()
则 ++(--e) == container.end()
为真。如果迭代器也满足 RandomAccessIterator,那么这些更一般的语句是有效的:
e - n
和 e -= n
用于 [ 0, container.size() ]< 中的任意整数 n /li>
e + n
和 e += n
用于 [ - container.size() , 0 ] 中的任意整数 n 因此,OP 中的 vector
示例不仅很好,正如其他答案所述,而且定义明确,保证适用于任何容器类型。
所以现在这里是我觉得缺少的一点。首先,从Container需求来看:
<块引用>表达 | 返回类型 | 语义 | 条件 | 复杂性 |
---|---|---|---|---|
a.end() |
(const_)迭代器 | 迭代器到 a | 的最后一个元素之后常数 |
这表示“超过最后一个元素”。但是,这是否意味着 end()
是可递减的?我们需要确定。下面的项目在这里很重要,我已经给它们编号以供参考:
end()
返回一个超过上述a”要求的结尾。i - n
,根据 -=
定义,没有给出任何约束。r -= n
,根据 +=
定义,没有给出任何约束。r += n
,根据 --r
的 n < 0
定义,没有给出任何约束。--a
a == ++b
。--(++a) == a
--a == --b
then a == b
a
和 --a
是同一个迭代器实例。size()
在语义上等同于 std::distance(begin(), end())
distance
:返回从first
到last
的增量。分解:
(5) 的先决条件表明,要使 --a
起作用,a 必须是可递减的,然后继续定义迭代器 如果存在 b 使得 ++ b == a
.
(1) 的“最后一个”语言似乎暗示如果 b 是容器中最后一个元素的迭代器,则 {{1 }}。然而,更令人信服的是,(7)表明 ++ b == end()
必须有效,因此(8)意味着 std::distance(begin(), end())
返回的迭代器必须能够重复递增,直到它等于 begin()
,这意味着对于非空容器,在某个时刻必须存在一个 b 使得 end()
.
将这两者结合起来,表明 ++ b == end()
如果 end()
总是可递减的,因为总是有一个 b 使得 !empty()
(否则 {{ 1}}——因此 ++ b == end()
——将不满足其语义要求),这是可递减性的定义。另请注意,(6) 明确指出可递减迭代器不需要可取消引用,并说明了结束迭代器的可递减性。
此外,由于distance(begin(), end())
在size()
时是可递减的,那么(其中end()
被初始化为!empty()
的返回值):
e
是有效的,来自 (5)。container.end()
对于 -- e
是有效的,从 (4) 开始。e += n
对于 n <= 0
是有效的,从 (3) 开始。e -= n
对于 n >= 0
是有效的,来自 (2)。e - n
、n >= 0
和 +=
(上面指出的 n 的符号)都是根据重复应用 {{1} },这将 n 限制在容器的大小范围内,因为 -=
不可递减(根据递减性的定义),最终迭代器必须命中 -
。因此,只要在应用它的迭代器之前至少有 1 个元素,OP 中的 --
就是有效的(来自 (2))。
Decrementability vs. dereferenceability:请注意,这是有区别的。 (6) 指出概念是分开的。可递减性意味着 begin()
是有效的,可解引用性意味着 begin()
和 - 1
是有效的。在 OP 的 --i
示例中,虽然 *i
是可递减的,但它不可解引用(vector::end()
明确说明了这一点)。
哦,是的,我也写了 a test program 只是为了检查:
i->
应该在不触发任何断言的情况下运行。
希望对你有帮助。几乎所有这些都是我努力说服自己vector
确实有效