我确信我并不孤单,期望我可以按某种顺序向vector
或list
添加多个元素,然后可以使用迭代器来检索这些元素的顺序相同。例如,在:
#include <vector>
#include <cassert>
int main(int argc, char **argv)
{
using namespace std;
vector<int> v;
v.push_back(4);
v.push_back(10);
v.push_back(100);
auto i = v.begin();
assert(*i++ == 4);
assert(*i++ == 10);
assert(*i++ == 100);
return 0;
}
...所有断言都应该通过,程序应该正常终止(假设在构造向量或向元素添加元素时没有抛出std::bad_alloc
异常)。
但是,我无法将其与C ++标准中的任何要求进行协调(我正在考虑C ++ 11,但如果它们明显不同,也希望得到其他标准的答案)。< / p>
begin()
的要求只是(23.2.1第6段):
begin()返回一个引用容器中第一个元素的迭代器。
我正在寻找的是要求或要求的组合,而这些要求又在逻辑上要求,如果i = v.begin()
,那么++i
将引用向量中的第二个元素(假设这样的元素存在) - 或者甚至是迭代器的连续递增将返回向量中的每个元素的要求。
修改
更一般的问题是,标准中的哪些(如果有的话)文本要求成功递增通过在序列(有序或无序)上调用begin()
获得的迭代器实际访问序列的每个元素?
答案 0 :(得分:3)
标准中并没有直截了当的说明
如果i = v.begin(),则++ i将引用第二个元素 矢量。
但是,对于向量迭代器,为什么可以从标准草案N4527 24.2.1 / p5中的以下措辞来暗示它。一般来说[iterator.requirements.general]:
进一步满足积分要求的迭代器 值
n
和可解除引用的迭代器值a
和(a + n)
,*(a + n)
等效于*(addressof(*a) + n)
,称为连续 迭代器。
现在,std::vector
的迭代器满足此要求,因此我们可以暗示++i
等同于i + 1
,因此意味着addressof(*i) + 1
。由于其连续性,它确实是向量中的第二个元素。
编辑:
关于random
在C ++ 11和C ++ 14标准中访问迭代器和连续存储容器的问题确实存在浑浊。因此,commity决定通过添加一组名为连续迭代器的额外迭代器来优化它们。您可以在相对提案N3884中找到更多信息。
答案 1 :(得分:1)
在我看来,我们需要将标准的两个独立部分放在一起,以便在此获得可靠的要求。我们可以从表101开始,这要求a[n]
等同于*(a.begin() + n)
的序列容器(具体来说,basic_string
,array
,deqeue
和{{1 (和vector
的相同要求,对于相同的容器)。
然后我们查看[random.access.iterators]中的表111,它要求表达式a.at(n)
等同于:
r += n
[缩进添加]
在这两者之间,这些暗示对于任何{
difference_type m = n;
if (m >= 0)
while (m--)
++r;
else
while (m++)
--r;
return r;
}
,n
指的是向量中的n th 项。如果你想要覆盖我看到的最后一个基础,我们将涵盖*(begin() + n)
实际附加到该集合的要求。这也在表101中:push_back
&#34;附加t&#34; (同样适用于a.push_back(t)
,basic_string
,string
,deque
和list
)。
答案 2 :(得分:0)
[C++14: 23.2.3/1]:
序列容器将所有相同类型的有限对象组织成严格的线性排列。 [..]
我不知道你怎么解释它。
答案 3 :(得分:0)
规范不仅仅在迭代器中。它也在容器的规范中,以及修改这些容器的操作。
问题是,你不会找到一个单独的条款,说“反复递增begin()
将按顺序访问向量的所有元素”。您需要查看每个容器上每个操作的规范(因为它们定义了容器中元素的顺序)和迭代器的规范(以及它们上的操作),这基本上是“递增移动到顺序中的下一个元素”对容器的操作定义,直到我们通过结束“。它是标准中众多条款的组合,可以产生最终效果。
然而,一般概念是....
所有容器都保持零个或多个元素的范围。该范围有三个关键属性:一个开头(对应于对容器有意义的顺序中的第一个元素),一个结束(对应于最后一个元素)和一个顺序(确定元素的顺序)一个接一个地检索 - 即定义“下一个”的含义)。
迭代器是一个对象,它引用一个范围中的元素,或者具有“超过结束”值。引用除结束(最后)之外的范围内的元素的迭代器,当递增时,将引用下一个元素。引用范围中的结束(最后)元素的迭代器,当递增时,将是结束(超过结束)迭代器。
begin()
方法返回一个迭代器,它引用(或指向)范围中的第一个(如果范围为零元素,则返回结束迭代器)。 end()
方法返回一个结束迭代器 - 一个对应于“一个超出范围结束”的迭代器。这意味着,如果使用begin()
初始化迭代器,则重复递增它将在整个范围内按顺序移动,直到达到结束迭代器。
然后有必要查看容器的各种修饰符的规范 - 添加或删除元素的成员函数。例如,push_back()
被指定为将元素添加到该容器的现有范围的末尾。它通过在末尾添加元素来扩展范围。
规范的组合 - 迭代器和修改容器的操作 - 保证了订单。实际效果是,如果元素按某种顺序添加到容器中,那么使用begin()
初始化的迭代器将 - 当重复递增时 - 按照它们放置在容器中的顺序引用元素。
显然,一些容器修饰符稍微复杂一些 - 例如,std::vector
的{{1}}被赋予一个迭代器,并在那里添加元素,随后移动元素以腾出空间。但是,关键点在于修饰符以定义的顺序将元素放入容器中(或者在像insert()
这样的操作的情况下删除),迭代器将按照定义的顺序访问元素。