C ++ STL向量:从索引获取迭代器?


200

因此,我编写了一堆代码通过index []访问stl向量中的元素,但是现在我只需要复制向量的一部分即可。看起来vector.insert(pos, first, last)是我想要的功能...除了我只有第一个和最后一个作为整数。有什么好方法可以让我迭代这些值?



如果我没看错,那么答案都不会进行任何边界检查,这可能是一个问题。具体来说,std :: advance文档说,如果您使用该行为来超越基础容器边界,则该行为是不确定的。
马丁·佩卡

Answers:


292

试试这个:

vector<Type>::iterator nth = v.begin() + index;

4
通常,STL迭代器可以使用与指针相同的算法。它们被设计为在使用STL算法时可以互换。
文森特·罗伯特,2009年

17
@VincentRobert:其他方法。指针是STL随机迭代器(最强大的类别)的有效实现。但是其他功能较弱的类别(例如前向迭代器)不支持相同的算法。
MSalters 2013年

6
我想让我的答案加我的5美分并推荐std::next(v.begin(), index)
stryku

86

@dirkgently提到的方式( v.begin() + index )对矢量来说很好且快速

但是大多数通用方法和随机访问迭代器也可以恒定时间工作。 std::advance( v.begin(), index )

EDIT
用法上的差异:

std::vector<>::iterator it = ( v.begin() + index );

要么

std::vector<>::iterator it = v.begin();
std::advance( it, index );

在@litb注释之后添加。


std :: advance是否不需要非常量迭代器作为第一个参数?
goldPseudo

您可以将std :: advance与const和非const迭代器一起使用
bayda

1
您不应该在这方面信任msvc。它具有非标准扩展名,使其可以接受此类内容,但是所有其他编译器均遵循标准并拒绝它。
Johannes Schaub-litb

1
我认为问题在于对“ const”含义的困惑:Advance()将很乐于在const_iterator <T>上工作,它是一个可变迭代器,它引用类型T的const元素;它不适用于本身为const的迭代器对象(即“ const iterator <T>”或“ iterator <T> const”)。
j_random_hacker 2009年

7
如果您知道要使用a std::vector,则没有必要使用std::advance。它只会引诱您以为您正在编写与容器无关的代码(您不必这样做,而要考虑迭代器失效规则,不同的运行时复杂性等等)。唯一std::advance有意义的情况是当您自己编写模板时不知道它要处理哪种迭代器。
Frerich Raabe 2013年

47

也; auto it = std::next(v.begin(), index);

更新:需要兼容C ++ 11x的编译器


2
应该注意的是,这是C ++ 11的方式!std :: next等同于std :: advance。使用这些函数而不是使用算术使交换容器类型变得更加容易。甚至可以对c数组afaik起作用,就像std :: begin和std :: end一样。
Zoomulator'5

2
还应该注意,std :: advance是由白痴设计的,因为它使用引用作为输出,而不是返回值。
维克多·瑟

1
for(auto it = begin(c); it!= end(c); advance(it,n)){...}
Zoomulator 2013年

2
两者都有其用途。stda :: advance对于更改迭代器非常有用。这是循环中的性能问题。正如您所建议的,我更喜欢下一个任务。我只是觉得它有点愚蠢而觉得有点苛刻。两种功能在设计时都考虑了不同的情况,即使它们基本相同。
Zoomulator 2013年

5
@Zoomulator:如果复制迭代器是出于性能方面的考虑,则您有更大的问题要处理。
Mooing Duck


-3

实际上,std :: vector在需要时可用作C选项卡。(据我所知,C ++标准要求用于矢量实现- 替换Wikipedia中的数组)例如,按照我的说法,这样做绝对是合法的:

int main()
{

void foo(const char *);

sdt::vector<char> vec;
vec.push_back('h');
vec.push_back('e');
vec.push_back('l');
vec.push_back('l');
vec.push_back('o');
vec.push_back('/0');

foo(&vec[0]);
}

当然,foo一定不能复制作为参数传递的地址并将其存储在某个地方,或者您应该确保在程序中不要将任何新项目压入vec或请求更改其容量。或风险细分错误...

因此,在您的例子中,它导致

vector.insert(pos, &vec[first_index], &vec[last_index]);

让我想知道为什么他们决定仅将迭代器抽象为迭代器……它们实际上是在“隐藏”这些功能。
mpen

为了方便?因为它可以让您轻松删除代码中任何其他类型容器的矢量实例。
伊夫·鲍美斯

4
&vec [i]产生的指针不一定与vector <> :: iterator兼容。vec.begin()+ i仍然具有成为您的库定义的任何迭代器的好处-例如,包括在调试模式下检查的迭代器。因此,如果不需要指针(例如,对于I / O),则应始终喜欢使用迭代器。
sellibitze

@KerrekSB来自c ++标准草案中的23.3.6.1:“向量的元素是连续存储的,这意味着如果v是向量<T,Allocator>,其中T是bool以外的某种类型,则它遵循&v [ n] ==&v [0] + n对于所有0 <= n <v.size()“
yves Baumes 2012年

2
@yvesBaumes:与向量迭代器无关。但是,裸指针也确实迭代器,它们不是矢量迭代器,这是事实。
Kerrek SB 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.