web-dev-qa-db-fra.com

Dois-je utiliser la nouvelle fonctionnalité "auto" de C ++ 11, en particulier dans les boucles?

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.

20
User

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.

40
DeadMG

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.

28
kevin cline

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 .

14
Konrad Rudolph

PRO

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.


CON

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;
11
BЈовић

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.

6
zvrba

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:

  • Cela ne vous oblige pas à taper des choses que le compilateur connaît déjà.
  • Il fait que le type de variables "suit" tout changement dans les types de valeur de retour.
  • Ce faisant, il empêche introduction silencieuse des conversions implicites et du découpage dans l'initialisation de la variable locale.
  • Il supprime la nécessité de certains calculs de type explicites dans les modèles.
  • Il supprime le besoin de nommer les types de retour avec des noms longs. (ceux que vous copiez-collez à partir des diagnostics du compilateur)

C'est là que vous avez le choix. Il y a aussi des cas où vous n'avez pas le choix:

  • Il permet la déclaration de variables de types inexprimables, comme le type d'un lambda.

Pourvu que vous sachiez exactement ce que fait auto, cela n'a aucun inconvénient.

4
Laurent LA RIZZA