Wektory C ++ STL: pobrać iterator z indeksu?

200

Napisałem więc sporo kodu, który uzyskuje dostęp do elementów w wektorze stl według indeksu [], ale teraz muszę skopiować tylko fragment wektora. Wygląda na vector.insert(pos, first, last)to, że jest to funkcja, której chcę ... ale mam tylko pierwszą i ostatnią jako ints. Czy jest jakiś fajny sposób na uzyskanie iteratora tych wartości?

mpen
źródło
1
Zobacz także: stackoverflow.com/q/2152986/365102
Mateen Ulhaq
Jeśli się nie mylę, żadna z odpowiedzi nie sprawdza granic, co może być problemem. Dokumenty std :: zaawansowane mówią w szczególności, że zachowanie jest niezdefiniowane, jeśli użyjesz go do przekroczenia podstawowych granic kontenera.
Martin Pecka

Odpowiedzi:

293

Spróbuj tego:

vector<Type>::iterator nth = v.begin() + index;
bezpośrednio
źródło
4
Zasadniczo można używać tej samej arytmetyki z iteratorami STL niż ze wskaźnikami. Zostały zaprojektowane tak, aby były wymienialne przy użyciu algorytmów STL.
Vincent Robert
18
@VincentRobert: Odwrotnie. Wskaźniki są prawidłowymi implementacjami losowych iteratorów STL, najpotężniejszej kategorii. Ale inne, słabsze kategorie, takie jak iteratory do przodu, nie obsługują tej samej arytmetyki.
MSalters
6
Chciałbym dodać moje pięć centów do tej odpowiedzi i polecićstd::next(v.begin(), index)
stryku
87

sposób wspomniany przez @dirkgently ( v.begin() + index )ładnie i szybko dla wektorów

ale najbardziej ogólny sposób i dla iteratorów o dostępie swobodnym działa również w stałym czasie. std::advance( v.begin(), index )

EDYTUJ
różnice w użyciu:

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

lub

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

dodane po notatkach @litb.

bayda
źródło
czy std :: Adv nie wymaga iteratora non-const jako pierwszego argumentu?
goldPseudo
możesz używać std :: Advance z iteratorami const i non-const
bayda
1
nie powinieneś ufać msvc w tym względzie. ma niestandardowe rozszerzenie, które sprawia, że ​​akceptuje to, jednak wszystkie inne kompilatory zachowują się normalnie i odmawiają.
Johannes Schaub - litb
1
Myślę, że problemem jest zamieszanie nad znaczeniem „const”: Advance () z radością zadziała na const_iterator <T>, który jest zmiennym iteratorem, który odnosi się do elementu const typu T; nie będzie działać na obiekcie iteratora, który sam jest const (tj. „const iterator <T>” lub „iterator <T> const”).
j_random_hacker
7
Jeśli wiesz, że masz do czynienia z std::vector, nie ma sensu używać std::advance. To tylko zachęca cię do myślenia, że ​​piszesz kod niezależny od kontenera (czego nie robisz, myśląc o regułach unieważniania iteratora, różnych złożonościach środowiska uruchomieniowego i tak dalej). Jedynym przypadkiem, gdy std::advancema to sens, jest samodzielne napisanie szablonu, który nie wie, z jakim typem iteratora ma do czynienia.
Frerich Raabe,
47

Również; auto it = std::next(v.begin(), index);

Aktualizacja: Potrzebuje kompilatora zgodnego z C ++ 11x

Viktor Sehr
źródło
2
Należy zauważyć, że jest to sposób C ++ 11! std :: next jest równoważne std :: Advance. Korzystanie z tych funkcji zamiast arytmetyki znacznie ułatwia wymianę typów kontenerów. Działa nawet na c-tablicach afaik, podobnie jak std :: begin i std :: end.
Zoomulator
2
Należy również zauważyć, że std :: Advant jest zaprojektowany przez idioty, ponieważ wykorzystuje referencję jako wynik, a nie wartość zwracaną.
Viktor Sehr
1
dla (! auto it = rozpocząć (C); to = koniec (c) zaliczki (to, n)) {...}
Zoomulator
2
Oba mają swoje zastosowania. Stda :: Advance jest przydatny do zmiany iteratora. Problem dotyczy wydajności w pętlach. Wolę następną w przypadku zadania, jak sugerujesz. Po prostu uważam, że to trochę surowe, twierdząc, że jest idiotyczne. Obie funkcje zostały zaprojektowane z myślą o różnych sytuacjach, mimo że w zasadzie są takie same.
Zoomulator,
5
@Zoomulator: jeśli kopiowanie iteratora ma wpływ na wydajność, masz większe problemy do rozwiązania.
Mooing Duck
8

Lub możesz użyć std::advance

vector<int>::iterator i = L.begin();
advance(i, 2);
TimW
źródło
-3

W razie potrzeby std :: vector mają być używane jako tabulatory C. (Standard C ++ wymaga, aby o implementację wektorową, o ile mi wiadomo - zastąpienie tablicy w Wikipedii ) Na przykład, według mnie, jest to całkowicie legalne:

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

Oczywiście albo foo nie może kopiować adresu przekazanego jako parametr i przechowywać go gdzieś, albo powinieneś zadbać o to, aby twój program nigdy nie wypychał żadnego nowego elementu w vec, ani nie prosił o zmianę jego pojemności. Lub błąd segmentacji ryzyka ...

Dlatego w twoim przykładzie prowadzi to do

vector.insert(pos, &vec[first_index], &vec[last_index]);
yves Baumes
źródło
Zastanawiam się, dlaczego postanowili oderwać się od iteratorów, jeśli są tylko wskaźnikami ... w zasadzie „ukrywają” te możliwości.
mpen
Dla spójności? Ponieważ pozwoliłoby to łatwo usunąć instancję wektorową dla dowolnego innego rodzaju kontenera w kodzie, więc.
yves Baumes
4
& vec [i] daje wskaźnik, który niekoniecznie jest zgodny z wektorem vector <> :: iterator. vec.begin () + i nadal ma tę zaletę, że może być dowolnym iteratorem, który określa biblioteka - na przykład sprawdzonymi iteratorami w trybie debugowania. Jeśli więc nie potrzebujesz wskaźnika (na przykład we / wy), zawsze powinieneś preferować iteratory.
sellibitze
@KerrekSB Od 23.3.6.1 w standardowej wersji c ++: „Elementy wektora są przechowywane w sposób ciągły, co oznacza, że ​​jeśli v jest wektorem <T, Alokator>, gdzie T jest innego typu niż bool, to jest on posłuszny tożsamości i v [ n] == & v [0] + n dla wszystkich 0 <= n <v.size () "
yves Baumes,
2
@yvesBaumes: nie ma to nic wspólnego z iteratorami wektorów. Prawdą jest jednak, że nagie wskaźniki również iteratorami - nie są to po prostu iteratory wektorowe .
Kerrek SB,