Vecteurs C ++ STL: obtenir l'itérateur de l'index?

201

J'ai donc écrit un tas de code qui accède aux éléments d'un vecteur stl par index [], mais maintenant je dois copier juste une partie du vecteur. Il ressemble à vector.insert(pos, first, last)la fonction que je veux ... sauf que je n'ai que le premier et le dernier en tant qu'ints. Existe-t-il un moyen agréable d'obtenir un itérateur pour ces valeurs?

mpen
la source
1
Voir aussi: stackoverflow.com/q/2152986/365102
Mateen Ulhaq
Si je ne me trompe pas, aucune des réponses ne vérifie les limites, ce qui pourrait être un problème. Plus précisément, les documents std :: advance indiquent que le comportement n'est pas défini si vous l'utilisez pour dépasser les limites du conteneur sous-jacent.
Martin Pecka

Réponses:

293

Essaye ça:

vector<Type>::iterator nth = v.begin() + index;
dirkgently
la source
4
En règle générale, vous pouvez utiliser la même arithmétique avec les itérateurs STL qu'avec les pointeurs. Ils sont conçus pour être échangeables lors de l'utilisation d'algorithmes STL.
Vincent Robert
18
@VincentRobert: Sinon. Les pointeurs sont des implémentations valides d'itérateurs aléatoires STL, la catégorie la plus puissante. Mais d'autres catégories moins puissantes telles que les itérateurs avancés ne prennent pas en charge la même arithmétique.
MSalters
6
Je voudrais ajouter mes cinq cents à cette réponse et recommanderstd::next(v.begin(), index)
stryku
88

manière mentionnée par @dirkgently ( v.begin() + index )sympa et rapide pour les vecteurs

mais la manière la plus générique et pour les itérateurs d'accès aléatoire fonctionne aussi à temps constant. std::advance( v.begin(), index )

MODIFIER les
différences d'utilisation:

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

ou

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

ajouté après les notes @litb.

bayda
la source
std :: advance n'a-t-il pas besoin d'un itérateur non const comme premier argument?
goldPseudo
vous pouvez utiliser std :: advance avec des itérateurs const et non const
bayda
1
vous ne devez pas faire confiance à msvc à cet égard. il a une extension non standard qui le fait accepter ce genre de chose, néanmoins tous les autres compilateurs se comportent en standard et le refusent.
Johannes Schaub - litb
1
Je pense que le problème est la confusion sur la signification de "const": Advance () fonctionnera avec plaisir sur un const_iterator <T>, qui est un itérateur mutable qui fait référence à un élément const de type T; il ne fonctionnera pas sur un objet itérateur qui est lui-même const (ie "const iterator <T>" ou "iterator <T> const").
j_random_hacker
7
Si vous savez que vous avez affaire à un std::vector, il est inutile de l'utiliser std::advance. Cela ne fait que vous inciter à penser que vous écrivez du code indépendant du conteneur (ce que vous ne faites pas, en pensant aux règles d'invalidation de l'itérateur, aux différentes complexités d'exécution et ainsi de suite). Le seul cas où std::advancecela a du sens est lorsque vous écrivez vous-même un modèle qui ne sait pas de quel type d'itérateur il s'agit.
Frerich Raabe
47

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

Mise à jour: nécessite un compilateur compatible C ++ 11x

Viktor Sehr
la source
2
Il est à noter que c'est la façon C ++ 11! std :: next est équivalent à std :: advance. L'utilisation de ces fonctions plutôt que l'utilisation d'arithmétiques facilite l'échange de types de conteneurs. Fonctionne même sur les tableaux c afaik, tout comme std :: begin et std :: end.
Zoomulator
2
Il convient également de noter que std :: advance est conçu par un idiot car il utilise une référence en sortie, et non la valeur de retour.
Viktor Sehr
1
for (auto it = begin (c); it! = end (c); advance (it, n)) {...}
Zoomulator
2
Les deux ont leur utilité. stda :: Advance est utile pour modifier l'itérateur en place. C'est un problème de performances dans les boucles. Je préfère ensuite en cas d'affectation, comme vous le suggérez. Je l'ai juste trouvé un peu dur en prétendant que c'était idiot. Les deux fonctions ont été conçues avec des situations différentes à l'esprit, même si elles sont fondamentalement les mêmes.
Zoomulator
5
@Zoomulator: si la copie de votre itérateur est un problème de performances, vous avez de plus gros problèmes à résoudre.
Mooing Duck
8

Ou vous pouvez utiliser std::advance

vector<int>::iterator i = L.begin();
advance(i, 2);
TimW
la source
-3

En fait, std :: vector est destiné à être utilisé comme onglet C en cas de besoin. (La norme C ++ demande cela pour l'implémentation des vecteurs, pour autant que je sache - remplacement du tableau dans Wikipedia ) Par exemple, il est parfaitement légal de faire cela, selon moi:

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

Bien sûr, soit foo ne doit pas copier l'adresse passée en tant que paramètre et la stocker quelque part, soit vous devez vous assurer dans votre programme de ne jamais pousser de nouvel élément dans vec, ou demander de changer sa capacité. Ou risque de faute de segmentation ...

Par conséquent, dans votre exemple, cela conduit à

vector.insert(pos, &vec[first_index], &vec[last_index]);
yves Baumes
la source
Je me demande pourquoi ils ont décidé d'abstraire les itérateurs s'ils ne sont que des pointeurs ... ils "cachent" essentiellement ces capacités.
mpen
Pour la cohérence? Comme cela vous permettrait de supprimer facilement l'instance de vecteur pour tout autre type de conteneur dans votre code.
yves Baumes
4
& vec [i] donne un pointeur qui n'est pas nécessairement compatible avec vector <> :: iterator. vec.begin () + i a toujours l'avantage d'être l'itérateur que votre bibliothèque le définit - y compris les itérateurs vérifiés en mode débogage, par exemple. Donc, si vous n'avez pas besoin d'un pointeur (pour les E / S par exemple), vous devriez toujours préférer les itérateurs.
sellibitze
@KerrekSB À partir du 23.3.6.1 dans le projet standard c ++: "Les éléments d'un vecteur sont stockés de manière contiguë, ce qui signifie que si v est un vecteur <T, Allocator> où T est un type autre que bool, il obéit à l'identité & v [ n] == & v [0] + n pour tous 0 <= n <v.size () "
yves Baumes
2
@yvesBaumes: cela n'a rien à voir avec les itérateurs vectoriels. Cependant, il est vrai que les pointeurs nus sont également des itérateurs - ils ne sont tout simplement pas des itérateurs vectoriels .
Kerrek SB