web-dev-qa-db-fra.com

Comment incrémenter un itérateur de 2?

Quelqu'un peut-il me dire comment incrémenter l'itérateur de 2?

iter++ est disponible - dois-je faire iter+2? Comment puis-je atteindre cet objectif?

57
Cute

std::advance( iter, 2 );

Cette méthode fonctionnera pour les itérateurs qui ne sont pas des itérateurs à accès aléatoire, mais elle peut toujours être spécialisée par l'implémentation pour ne pas être moins efficace que iter += 2 lorsqu'elle est utilisée avec des itérateurs à accès aléatoire.

86
CB Bailey

http://www.cplusplus.com/reference/std/iterator/advance/

std::advance(it,n);

où n est 2 dans votre cas.

La beauté de cette fonction est que, si "il" est un itérateur à accès aléatoire, le

it += n

l’opération est utilisée (c’est-à-dire le vecteur <,> :: iterator). Sinon, son rendu à

for(int i = 0; i < n; i++)
    ++it;

(c'est-à-dire la liste <..> :: iterator)

23
Maik Beckmann

Si vous ne possédez pas la valeur modifiable d'un itérateur ou si vous souhaitez obtenir une copie d'un itérateur donné (sans modifier l'original), C++ 11 est accompagné de nouvelles fonctions d'assistance - std::next / std::prev :

std::next(iter, 2);          // returns a copy of iter incremented by 2
std::next(std::begin(v), 2); // returns a copy of begin(v) incremented by 2
std::prev(iter, 2);          // returns a copy of iter decremented by 2
13
Piotr Skotnicki

Vous pouvez utiliser l'opérateur 'affectation par addition'

iter += 2;
7
teabot

Si vous ne savez pas si vous avez suffisamment d'éléments suivants dans votre conteneur, vous devez vérifier la fin de votre conteneur entre chaque incrément. Ni ++ ni std :: advance ne le feront pour vous.

if( ++iter == collection.end())
  ... // stop

if( ++iter == collection.end())
  ... // stop

Vous pouvez même lancer votre propre fonction d'avance liée sécurisée.

Si vous êtes sûr de ne pas dépasser la fin, std :: advance (iter, 2) est la meilleure solution.

4
Jem

Nous pouvons utiliser à la fois avance et suivant. Mais, il y a une différence entre les deux. "advance" modifie son argument et ne renvoie rien. Alors, il peut être utilisé comme: 

vector<int> v;
v.Push_back(1);
v.Push_back(2);
auto itr = v.begin();
advance(itr, 1);           //modifies the itr
cout << *itr<<endl        //prints 2

"next" renvoie une copie modifiée de l'itérateur

vector<int> v;
v.Push_back(1);
v.Push_back(2);
cout << *next(v.begin(), 1) << endl;    //prints 2
1
skpro19

En supposant que la taille de la liste ne soit pas un multiple de l’étape, vous devez vous prémunir contre le débordement:

static constexpr auto step = 2;

// Guard against invalid initial iterator.
if (!list.empty())
{
    for (auto it = list.begin(); /*nothing here*/; std::advance(it, step))
    {
        // do stuff...

        // Guard against advance past end of iterator.
        if (std::distance(it, list.end()) > step)
            break;
    }
}

Selon l'implémentation de la collection, le calcul de la distance peut être très lent. Ci-dessous est optimal et plus lisible. La fermeture pourrait être changée en un modèle d'utilitaire avec la valeur de fin de liste passée par la référence const:

const auto advance = [&](list_type::iterator& it, size_t step)
{
    for (size_t i = 0; it != list.end() && i < step; std::next(it), ++i);
};

static constexpr auto step = 2;

for (auto it = list.begin(); it != list.end(); advance(it, step))
{
    // do stuff...
}

S'il n'y a pas de boucle:

static constexpr auto step = 2;
auto it = list.begin();

if (step <= list.size())
{
    std::advance(it, step);
}
0
evoskuil