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?



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;

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.


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


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


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

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,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.