Quelle est la bonne façon d'utiliser for
basé sur la plage de C++ 11?
Quelle syntaxe faut-il utiliser? for (auto elem : container)
ou for (auto& elem : container)
ou for (const auto& elem : container)
? Ou un autre?
Il n'y a pas de manière correcte d'utiliser for (auto elem : container)
ou for (auto& elem : container)
ou for (const auto& elem : container)
. Vous venez d'exprimer ce que vous voulez.
Laissez-moi élaborer sur cela. Faisons une promenade.
for (auto elem : container) ...
Celui-ci est un sucre syntaxique pour:
for(auto it = container.begin(); it != container.end(); ++it) {
// Observe that this is a copy by value.
auto elem = *it;
}
Vous pouvez utiliser celui-ci si votre conteneur contient des éléments peu coûteux à copier.
for (auto& elem : container) ...
Celui-ci est un sucre syntaxique pour:
for(auto it = container.begin(); it != container.end(); ++it) {
// Now you're directly modifying the elements
// because elem is an lvalue reference
auto& elem = *it;
}
Utilisez cette option lorsque vous souhaitez écrire directement sur les éléments du conteneur, par exemple.
for (const auto& elem : container) ...
Celui-ci est un sucre syntaxique pour:
for(auto it = container.begin(); it != container.end(); ++it) {
// You just want to read stuff, no modification
const auto& elem = *it;
}
Comme le dit le commentaire, juste pour lire. Et c'est à peu près tout, tout est "correct" lorsqu'il est utilisé correctement.
Le bon moyen est toujours
for(auto&& elem : container)
Cela garantira la préservation de toute la sémantique.
Bien que la motivation initiale de la boucle plage-pour-ait pu être la facilité d'itération sur les éléments d'un conteneur, la syntaxe est suffisamment générique pour être utile même pour des objets qui ne sont pas uniquement des conteneurs.
La condition syntaxique de la boucle for est que range_expression
prenne en charge begin()
et end()
en tant que fonctions - en tant que fonctions membres du type évalué ou en tant que fonctions non membres prenez une instance du type.
A titre d'exemple, on peut générer une plage de nombres et effectuer une itération sur la plage en utilisant la classe suivante.
struct Range
{
struct Iterator
{
Iterator(int v, int s) : val(v), step(s) {}
int operator*() const
{
return val;
}
Iterator& operator++()
{
val += step;
return *this;
}
bool operator!=(Iterator const& rhs) const
{
return (this->val < rhs.val);
}
int val;
int step;
};
Range(int l, int h, int s=1) : low(l), high(h), step(s) {}
Iterator begin() const
{
return Iterator(low, step);
}
Iterator end() const
{
return Iterator(high, 1);
}
int low, high, step;
};
Avec la fonction main
suivante,
#include <iostream>
int main()
{
Range r1(1, 10);
for ( auto item : r1 )
{
std::cout << item << " ";
}
std::cout << std::endl;
Range r2(1, 20, 2);
for ( auto item : r2 )
{
std::cout << item << " ";
}
std::cout << std::endl;
Range r3(1, 20, 3);
for ( auto item : r3 )
{
std::cout << item << " ";
}
std::cout << std::endl;
}
on obtiendrait la sortie suivante.
1 2 3 4 5 6 7 8 9
1 3 5 7 9 11 13 15 17 19
1 4 7 10 13 16 19