2017-08-02 5 views
0

J'utilise un std::vector avec C++ pour stocker quelques éléments & les récupérer plus tard. Voici comment je parcours mon vecteur.Comment faire une boucle à travers un std :: vecteur dans les cycles répétitifs

std::vector<some_object> some_vector; 
some_vector.resize(10); 

for (auto it = some_vector.begin(); it != some_vector.end(); ++it) { 
    int current_it_index = std::distance(some_vector.begin(), it); 
} 

J'ai besoin de l'index par itération. Donc, en le récupérant par itération comme démontré ci-dessus.

Au-dessus de la boucle fonctionne bien mais je veux boucle à travers le vecteur dans les cycles infinis. Comment puis je faire ça?

Maintenant, je comprends que la question vient, Comment arrêtez-vous la boucle en cours d'exécution si vous le laissez fonctionner en répétant des cycles. Je pense à utiliser un std::atomic<bool> comme une variable pour signaler & sortir de la boucle qui devrait fonctionner plutôt bien?

PS: Notez que j'ai pris std::vector comme exemple de conteneur pour expliquer la question. Ce serait génial si la solution suggérée pouvait fonctionner sur std::array ou d'autres conteneurs.

+3

Une boucle 'while' simple ferait l'affaire. Ne le surchargez pas, il vous suffit d'envelopper votre boucle 'for' actuelle dans une boucle' while' qui vérifiera le 'std :: atomic '. Cependant, il pourrait être fait en utilisant seulement la boucle 'for' que vous avez déjà, vous avez juste besoin de changer deux choses: 1) Réinitialiser l'itérateur à la fin, 2) vérifier le' std :: atomique 'que vous avez mentionné afin de savoir quand arrêter. – DimChtz

+1

Voulez-vous que 'current_it_index' revienne à' 0' après avoir recommencé à parcourir le vecteur ou devrait-il continuer à augmenter? Aussi ce genre de sons ressemble à un problème XY. Si vous nous dites pourquoi vous faites cela, nous serons peut-être en mesure de vous indiquer quelque chose de différent. – NathanOliver

+0

J'ai compris. 'pour (auto it = some_vector.begin(); ++ ++) { int current_it_index = std :: distance (some_vector.begin(), it); if (it == some_vector.end() -1) it = un_vector.begin(); } ' –

Répondre

3
std::vector<some_object> some_vector; 
some_vector.resize(10); 
bool quit = false; 
while (!quit) { 
    for (auto& e:some_vector) { 
    if (quit) break; 
    std::size_t i = std::addressof(e)-some_vector.data(); 
    // ... 
    } 
} 
1

Une astuce courante pour itérer à travers un tableau qui a une puissance de 2 nombre d'éléments consiste simplement à itérer un compteur et à utiliser une opération de masque.

size_t counter = 0; 
const size_t mask = some_vector.size() - 1U; 

while (!quit) { 
    size_t i = counter++ & mask; 
    do_something(some_vector[i]); 
} 

Si le tableau n'est pas une puissance de deux, vous pourriez effectuer des opérations arithmétiques modulo au lieu de masquer un compteur de course libre.

size_t i = 0; 
const size_t n = some_vector.size(); 

while (!quit) { 
    do_something(some_vector[i++]); 
    i %= n; 
} 

Si vous utilisez un conteneur d'accès non aléatoire, et ont besoin d'itérateurs et les index, vous pouvez mettre en œuvre deux boucles. Cela éviterait le coût du calcul distance sur un itérateur d'accès non aléatoire.

for (;;) { 
    size_t idx = 0; 
    for (auto it = some_container.begin(); 
     it != some_container.end(); 
     ++it) { 
     do_something(it, idx++); 
    } 
+0

Ceci obtient un index au lieu d'un itérateur, qui pourrait fonctionner pour 'vector' mais ne fonctionne pas pour' list' ou toute autre structure de données non contiguë. –

+0

Cela fonctionnerait pour 'deque', qui n'est pas contigu. – jxh

+0

Assez juste; mon commentaire était imprécis. Ce n'était pas fondamentalement incorrect; cela ne fonctionne pas sans un 'opérateur []', 'at()', ou une autre méthode pour transformer un 'size_t' en élément. –

1

Si je comprends bien, ce que vous voulez est que lorsque vous obtenez au dernier élément de votre conteneur, vous sautez simplement au début du conteneur à nouveau. Nous pouvons facilement le code qui assez:

auto first = std::begin(c); 
const auto last = std::end(c); 
std::size_t idx = 0; 

while (!should_exit()) { 
    do_something(idx); 

    ++idx; 
    if (++first == last) { // reset 
     idx = 0; 
     first = std::begin(c); 
    } 
} 

Cela devrait fonctionner pour tout conteneur de type STL. Avoir à la fois l'itérateur et l'index est peut-être inutile, mais c'est une solution KISS qui fonctionnera pour les conteneurs à accès non-aléatoire comme std::list ainsi que vector/array.

+0

En général ce code a une confiance dangereuse que do_something() n'invalide pas les itérateurs (ou ne modifie pas le conteneur). –