Quels sont les avantages/inconvénients de l'utilisation du mot clé auto
, en particulier dans les boucles for?
for(std::vector<T>::iterator it = x.begin(); it != x.end(); it++ )
{
it->something();
}
for(std::map<T>::iterator it = x.begin(); it != x.end(); it++ )
{
it->second->something();
}
for(auto it = x.begin(); it != x.end(); it++ )
{
it->??
}
On dirait que si vous ne savez pas si vous avez un itérateur pour une carte ou un vecteur, vous ne savez pas si vous devez utiliser first
ou second
ou simplement accéder directement aux propriétés de l'objet, non ?
Cela me rappelle le débat C # sur l'opportunité d'utiliser le mot clé var
. L'impression que j'ai jusqu'à présent est que dans le monde C++, les gens sont prêts à adopter le mot clé auto
avec moins de combat que var
dans le monde C #. Pour moi, mon premier instinct est que j'aime connaître le type de la variable afin que je puisse savoir quelles opérations je peux m'attendre à y effectuer.
Les motivations en C++ sont plus extrêmes, car les types peuvent devenir beaucoup plus compliqués et complexes que les types C # en raison de la métaprogrammation et d'autres choses. auto
est plus rapide à écrire et à lire et plus flexible/maintenable qu'un type explicite. Je veux dire, voulez-vous commencer à taper
boost::multi_map<NodeType, indexed_by<ordered_unique<identity<NodeType>>, hashed_non_unique<identity<NodeType>, custom_hasher>>::iterator_type<0> it
Ce n'est même pas le type complet. J'ai raté quelques arguments de modèle.
Dans votre exemple:
for(auto it = x.begin(); it != x.end(); i++)
{
it->??
}
il doit y avoir une déclaration pour x
visible. Par conséquent, le type de it
devrait être évident. Si le type de x
n'est pas évident, alors la méthode est trop longue ou la classe est trop grande.
Objection ! Question chargée.
Pouvez-vous m'expliquer pourquoi le troisième code a ??
dedans, mais pas le premier et le deuxième? Par souci d'équité, votre code doit se lit comme suit:
for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++)
{
it->???
}
for(std::map<T>::iterator it = x.begin(); it != x.end(); i++)
{
it->second->???
}
Là. Même problème même si vous n'avez pas utilisé auto
.
Et dans tous les cas, la réponse est la même: Le contexte compte . Vous ne pouvez pas parler de manière significative d'un morceau de code de manière isolée. Même si vous n'aviez pas utilisé de modèles mais un type concret, cela n'aurait fait que déplacer le problème ailleurs, car le lecteur de votre code devrait connaître la déclaration dudit type.
Si l'utilisation de auto
dans ces situations rend votre code illisible, vous devez le traiter comme un signe d'avertissement indiquant que quelque chose ne va pas dans la conception de votre code. Bien sûr, il y a des cas où des détails de bas niveau sont importants (comme pour les opérations sur les bits ou l'API héritée), auquel cas un type explicite peut faciliter la lisibilité. Mais en général - non.
Concernant var
(puisque vous l'avez explicitement mentionné), il y a aussi un vaste consensus dans la communauté C # pour utilisant var
. Les arguments contre son utilisation sont généralement construits sur des erreurs .
Votre code :
for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++)
ne va pas compiler, en raison du nom dépendant du modèle.
Voici la syntaxe correcte:
for( typename std::vector<T>::iterator it = x.begin(); it != x.end(); i++)
Regardez maintenant la longueur de la déclaration de type. Cela explique pourquoi le mot clé auto
a été introduit. Cette :
for( auto it = x.begin(); it != x.end(); i++)
est plus concis. Donc, c'est un pro.
Il faut être un peu prudent. Avec le mot clé auto
, vous obtenez le type que vous avez déclaré.
Par exemple :
std::vector< int > v{ 1, 2, 3, 4 };
for ( auto it : v )
{
++ it; // ops modifying copies of vector's elements
}
contre
std::vector< int > v{ 1, 2, 3, 4 };
for ( auto & it : v ) // mind the reference
{
++ it; // ok, vector's elements modified
}
Pour conclure: oui, vous devriez le faire, mais pas en abuser. Certaines personnes ont tendance à trop l'utiliser et à mettre l'auto partout, comme dans l'exemple suivant:
auto i = 0;
contre
int i = 0;
Oui tu devrais! auto
n'efface pas le type; même si vous "ne savez pas" ce qu'est x.begin()
, le compilateur sait et signalera une erreur si vous essayez d'utiliser le type incorrectement. De plus, il n'est pas rare d'émuler map
avec un vector<pair<Key,Value>>
, donc le code utilisant auto
fonctionnera pour les deux représentations de dictionnaire.
Oui, vous devez utiliser auto
comme règle par défaut. Il présente des avantages bruts par rapport à la spécification explicite du type:
C'est là que vous avez le choix. Il y a aussi des cas où vous n'avez pas le choix:
Pourvu que vous sachiez exactement ce que fait auto
, cela n'a aucun inconvénient.