240

So, I wrote a bunch of code that accesses elements in an stl vector by index[], but now I need to copy just a chunk of the vector. It looks like vector.insert(pos, first, last) is the function I want... except I only have first and last as ints. Is there any nice way I can get an iterator to these values?

Andy
  • 3,794
  • 24
  • 28
mpen
  • 272,448
  • 266
  • 850
  • 1,236
  • 1
    See also: http://stackoverflow.com/q/2152986/365102 – Mateen Ulhaq Nov 26 '11 at 11:02
  • If I'm not wrong, none of the answers does any bounds checks, which might be a problem. Specifically, std::advance docs say the behavior is undefined if you use it to get past the underlying container bounds. – Martin Pecka Oct 23 '19 at 12:27

5 Answers5

349

Try this:

vector<Type>::iterator nth = v.begin() + index;
dirkgently
  • 108,024
  • 16
  • 131
  • 187
  • 5
    Generally, you can use the same arithmetic with STL iterators than with pointers. They are designed to be exchangeable when using STL algorithms. – Vincent Robert Mar 22 '09 at 21:07
  • 20
    @VincentRobert: Other way around. Pointers are valid implementations of STL random iterators, the most powerful category. But other, less powerful categories such as forward iterators do not support the same arithmetic. – MSalters Jan 03 '13 at 09:29
  • 11
    I'd want ot add my five cents to this answer and recommend `std::next(v.begin(), index)` – stryku Nov 06 '17 at 18:42
102

way mentioned by @dirkgently ( v.begin() + index ) nice and fast for vectors

but std::advance( v.begin(), index ) most generic way and for random access iterators works constant time too.

EDIT
differences in usage:

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

or

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

added after @litb notes.

bayda
  • 13,365
  • 8
  • 39
  • 48
  • doesn't std::advance require a non-const iterator as the first argument? – goldPseudo Mar 22 '09 at 19:10
  • you can use std::advance with const and non-const iterators – bayda Mar 22 '09 at 19:23
  • bb, that page you linked says it requires a non-const reference. so better do vector::iterator it = v.begin(); advance(it, index); instead – Johannes Schaub - litb Mar 22 '09 at 19:54
  • where you see this requirement? – bayda Mar 22 '09 at 19:56
  • i wasn't clear with my wording. i mean it has a non-const reference as a parameter. it so requires lvalues as arguments. – Johannes Schaub - litb Mar 22 '09 at 19:59
  • @goldPseudo: on my stl from vc 2008, next code compiled w/o errors. std::vector< size_t >::const_iterator it = v.begin(); std::advance( it, 5 ); – bayda Mar 22 '09 at 20:02
  • bb, see: template void f(T&); f(1); /* bug, doesn't compile */ . you need a f(1); or just say int x; f(x); – Johannes Schaub - litb Mar 22 '09 at 20:05
  • 1
    you should not trust msvc in that regard. it has a non-standard extension that makes it accept this kind of thing, nevertheless all other compilers behave standard and refuse it. – Johannes Schaub - litb Mar 22 '09 at 20:06
  • yes, I agree, msvc compiling - was fast check. that about you saying: it works for const_iterator, for iterator ( by my link, and standard ), and it acepting non-const reference, because it will change this reference. – bayda Mar 22 '09 at 20:32
  • 1
    I think the problem is confusion over the meaning of "const": advance() will happily work on a const_iterator, which is a mutable iterator that refers to a const element of type T; it won't work on an iterator object which is itself const (i.e. "const iterator" or "iterator const"). – j_random_hacker Mar 23 '09 at 04:15
  • 7
    If you *know* that you're dealing with a `std::vector`, there's no point in using `std::advance`. It only lures you into thinking you're writing container-agnostic code (which you don't, thinking of iterator invalidation rules, different runtime complexities and whatnot). The only case when `std::advance` makes sense is when you write a template yourself which doesn't know what kind of iterator it's dealing with. – Frerich Raabe Aug 12 '13 at 07:54
61

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

Update: Needs a C++11x compliant compiler

Viktor Sehr
  • 12,825
  • 5
  • 58
  • 90
  • 3
    It should be noted that this is the C++11 way! std::next is equivalent to std::advance. Using these functions rather than using arithmetics makes swapping container types a lot easier. Even works on c-arrays afaik, just like std::begin and std::end. – Zoomulator May 02 '12 at 14:50
  • 1
    for( auto it=begin(c); it != end(c); advance(it, n) ) { ... } – Zoomulator Jan 02 '13 at 22:09
  • std::list lst; iterator fifth_element = *std::next(lst.begin(), 5); – Viktor Sehr Jan 03 '13 at 08:48
  • 3
    Both have their uses. stda::advance is useful for altering the iterator in place. It's a performance concern in loops. I'd prefer next in the case of assignment, as you suggest. I just found it a bit harsh claiming it to be idiotic. Both functions were designed with different situations in mind, even though they are basically the same. – Zoomulator Jan 03 '13 at 16:06
  • 6
    @Zoomulator: If copying your iterator is a performance concern, you have bigger issues to deal with. – Mooing Duck Nov 04 '14 at 19:40
10

You can always use std::advance to move the iterator a certain amount of positions in constant time:

std::vector<int>::iterator it = myvector.begin();
std::advance(it, 2);
SRG
  • 498
  • 7
  • 19
TimW
  • 8,351
  • 1
  • 29
  • 33
-3

Actutally std::vector are meant to be used as C tab when needed. (C++ standard requests that for vector implementation , as far as I know - replacement for array in Wikipedia) For instance it is perfectly legal to do this folowing, according to me:

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]);
}

Of course, either foo must not copy the address passed as a parameter and store it somewhere, or you should ensure in your program to never push any new item in vec, or requesting to change its capacity. Or risk segmentation fault...

Therefore in your exemple it leads to

vector.insert(pos, &vec[first_index], &vec[last_index]);
yves Baumes
  • 8,836
  • 7
  • 45
  • 74
  • 1
    Makes me wonder why they decided to abstract away to iterators if they're just pointers... they're essentially "hiding" these capabilities. – mpen Mar 27 '09 at 07:10
  • For consitency ? As it would allow you to easily remove vector instance for any other kind of container in your code so. – yves Baumes Mar 27 '09 at 21:53
  • 5
    &vec[i] yields a pointer which is not necessarily compatible with vector<>::iterator. vec.begin()+i still has the benefit of being whatever iterator your library defines it to be -- including checked iterators in debug mode, for example. So, if you don't need a pointer (for I/O for example), you should always prefer iterators. – sellibitze Sep 27 '09 at 08:01
  • @KerrekSB From 23.3.6.1 in the c++ standard draft: "The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size()" – yves Baumes Sep 17 '12 at 21:07
  • 2
    @yvesBaumes: that has nothing to do with vector iterators. However, it is true that naked pointers *are* also iterators -- they're just not *vector* iterators. – Kerrek SB Sep 17 '12 at 21:08
  • @KerrekSB As for my answer , which is about reference_type. – yves Baumes Sep 17 '12 at 21:10