Y a-t-il un inconvénient à déclarer des variables avec auto en C ++?

143

Il semble que autoc'était une fonctionnalité assez importante à ajouter dans C ++ 11 qui semble suivre un grand nombre des nouveaux langages. Comme avec un langage comme Python, je n'ai vu aucune déclaration de variable explicite (je ne sais pas si c'est possible en utilisant les standards Python).

Y a-t-il un inconvénient à utiliser autopour déclarer des variables au lieu de les déclarer explicitement?

DxAlpha
la source
1
Voir aussi: stackoverflow.com/questions/6434971/… , stackoverflow.com/questions/15254461/… , stackoverflow.com/questions/6900459/… , stackoverflow.com/questions/8430053/is-c11-auto-type-dangerous , et peut-être d'autres. Je ne sais pas si ce sont des doublons exacts, mais ce sont certainement des candidats.
Cody Gray
3
Le seul inconvénient que j'ai trouvé était lorsque j'ai dû porter une base de code sur une plate-forme (console) dont le compilateur ne supportait pas (et n'avait aucune intention de supporter) les fonctionnalités C ++ 11!
Sam
7
Juste pour être complet GotW # 94 "Almost Always Auto": herbsutter.com/2013/08/12/…
Richard Critten
1
J'écoutais cppcast et il y avait mention de clash b / w auto et des initialiseurs de liste. Je vais essayer de trouver ce podcast.
Abhinav Gauniyal le
2
le premier inconvénient, je pense, a un impact sur la lisibilité du code
ggrr

Réponses:

111

Vous avez seulement posé des questions sur les inconvénients, alors j'en souligne certains. Lorsqu'il est bien utilisé, il autoprésente également plusieurs avantages. Les inconvénients résultent de la facilité des abus et du potentiel accru du code à se comporter de manière non intentionnelle.

Le principal inconvénient est qu'en utilisant auto, vous ne connaissez pas nécessairement le type d'objet en cours de création. Il y a aussi des occasions où le programmeur peut s'attendre à ce que le compilateur déduise un type, mais le compilateur en déduit catégoriquement un autre.

Étant donné une déclaration comme

auto result = CallSomeFunction(x,y,z);

vous ne savez pas forcément quel type result s'agit. Cela pourrait être un int. Cela pourrait être un indicateur. Cela pourrait être autre chose. Tous ces éléments prennent en charge différentes opérations. Vous pouvez également modifier considérablement le code par un changement mineur comme

auto result = CallSomeFunction(a,y,z);

car, en fonction des surcharges existantes, CallSomeFunction()le type de résultat peut être complètement différent - et le code suivant peut donc se comporter complètement différemment de ce qui est prévu. Vous pourriez soudainement déclencher des messages d'erreur dans le code ultérieur (par exemple, essayer de déréférencer un int, essayer de changer quelque chose qui est maintenant const). Le changement le plus sinistre est celui où votre changement passe devant le compilateur, mais le code suivant se comporte de manière différente et inconnue - peut-être boguée.

Ne pas avoir de connaissance explicite du type de certaines variables rend donc plus difficile de justifier rigoureusement une affirmation selon laquelle le code fonctionne comme prévu. Cela signifie plus d'efforts pour justifier les allégations de «convenance à l'usage» dans les domaines de haute criticité (par exemple, critiques pour la sécurité ou la mission).

L'autre inconvénient, plus courant, est la tentation pour un programmeur d'utiliser autocomme un instrument brutal pour forcer le code à se compiler, plutôt que de penser à ce que le code fait et de travailler pour le faire correctement.

Peter
la source
58
Il est intéressant de noter que si de tels exemples sont l'inconvénient de l'utilisation auto, alors la plupart des langages typés canard souffrent d'un tel inconvénient par conception!
Leben Asa
11
Si CallSomeFunction()retourne un type différent selon la séquence de ses arguments, c'est un défaut de conception de CallSomeFunction(), pas un problème de auto. Si vous ne lisez pas la documentation d'une fonction que vous utilisez avant de l'utiliser, c'est un défaut du programmeur, pas un problème de auto. - Mais je comprends que vous jouez l'avocat du diable ici, c'est juste que Nir Friedman a le bien meilleur cas.
DevSolar
16
@DevSolar: Pourquoi serait T CallSomeFunction(T, int, int)un défaut de conception? De toute évidence, il "renvoie un type différent en fonction de la séquence de ses arguments".
MSalters
9
"Le principal inconvénient est qu'en utilisant auto, vous ne connaissez pas nécessairement le type d'objet en cours de création." Pouvez-vous expliquer pourquoi c'est un problème avec auto, et non un problème avec les sous-expressions temporaires? Pourquoi est-ce auto result = foo();mauvais, mais foo().bar()pas?
Angew n'est plus fier de SO
24
Il semble d'après les commentaires que «inconvénient» est interprété comme une raison pour laquelle quelque chose est inacceptable. Un inconvénient d'une fonctionnalité de langage est un inconvénient que le développeur doit prendre en compte et justifier l'acceptation ou non - c'est-à-dire faire des compromis d'ingénierie. Je ne fais pas de déclarations générales sur les raisons pour lesquelles la fonctionnalité devrait ou ne devrait pas être utilisée.
Peter
76

Ce n'est pas autoexactement un inconvénient de principe, mais en termes pratiques, cela semble être un problème pour certains. Fondamentalement, certaines personnes: a) se traitent autocomme un sauveur pour les types et bloquent leur cerveau lorsqu'elles l'utilisent, ou b) oublient que cela autodéduit toujours des types de valeur. Cela amène les gens à faire des choses comme ceci:

auto x = my_obj.method_that_returns_reference();

Oups, nous venons de copier en profondeur un objet. C'est souvent un bug ou un échec de performance. Ensuite, vous pouvez également basculer dans l'autre sens:

const auto& stuff = *func_that_returns_unique_ptr();

Maintenant, vous obtenez une référence pendante. Ces problèmes ne sont pas causés parauto , donc je ne les considère pas comme des arguments légitimes contre cela. Mais il semble que autoces problèmes soient plus courants (d'après mon expérience personnelle), pour les raisons que j'ai énumérées au début.

Je pense qu'avec le temps, les gens s'adapteront et comprendront la division du travail: en autodéduit le type sous-jacent, mais vous voulez toujours penser à la référence et à la constance. Mais cela prend un peu de temps.

Nir Friedman
la source
Pourquoi pouvez-vous copier en profondeur un objet coûteux pour commencer?
Laurent LA RIZZA
3
@LaurentLARIZZA: Certaines classes ont des constructeurs de copie simplement parce qu'ils sont parfois nécessaires (par exemple, des instances de std::vector). Le fait d'être coûteux à copier n'est pas une propriété d'une classe, mais des objets individuels. Cela method_that_returns_referencepourrait donc faire référence à un objet d'une classe qui a un constructeur de copie, mais dont l'objet s'avère assez coûteux à copier (et ne peut pas être déplacé).
Marc van Leeuwen
@MarcvanLeeuwen: Si l'objet est coûteux à copier et ne peut pas être déplacé, pourquoi serait-il stocké dans un std::vector? (Parce que cela pourrait, oui, ou parce que vous ne contrôlez pas la classe, mais ce n'est pas le but) Si la copie coûte cher (et ne possède aucune ressource, car elle est copiable), pourquoi ne pas utiliser COW sur l'objet? La localité de données est déjà tuée par la taille de l'objet.
Laurent LA RIZZA
2
@LaurentLARIZZA Ce n'est pas une instance de quelque chose stocké dans un vecteur qui est cher, juste un vecteur régulier par exemple <double> est cher à copier, c'est une allocation de tas + O (N) travail. Le déménagement est un hareng rouge. La première ligne que j'ai affichée sera copiée, pas déplacée, à moins que la référence renvoyée ne soit une référence rvalue. COW n'est vraiment ni ici ni là-bas. Le fait est que les objets coûteux à copier existeront toujours.
Nir Friedman le
4
@Yakk Il ne peut pas faire cela en toute sécurité, car il pourrait trancher. La seule chose sûre qu'il puisse faire est = deletecette surcharge. Bien que plus généralement ce que vous dites est une solution. C'est un sujet que j'ai exploré, si cela vous intéresse: nirfriedman.com/2016/01/18/… .
Nir Friedman
51

D'autres réponses mentionnent des inconvénients comme «vous ne savez pas vraiment quel est le type d'une variable». Je dirais que cela est largement lié à une convention de dénomination bâclée dans le code. Si vos interfaces sont clairement nommées, vous ne devriez pas avoir à vous soucier du type exact. Bien sûr, auto result = callSomeFunction(a, b);ça ne vous dit pas grand chose. Mais auto valid = isValid(xmlFile, schema);vous en dit assez pour l'utiliser validsans avoir à vous soucier de son type exact. Après tout, avec juste if (callSomeFunction(a, b)), vous ne sauriez pas non plus le type. La même chose avec tous les autres objets temporaires de sous-expression. Je ne considère donc pas cela comme un réel inconvénient auto.

Je dirais que son principal inconvénient est que parfois, le type de retour exact n'est pas celui avec lequel vous voulez travailler. En effet, le type de retour réel diffère parfois du type de retour "logique" en tant que détail d'implémentation / d'optimisation. Les modèles d'expression en sont un excellent exemple. Disons que nous avons ceci:

SomeType operator* (const Matrix &lhs, const Vector &rhs);

Logiquement, nous nous attendrions SomeTypeà l'être Vector, et nous voulons absolument le traiter comme tel dans notre code. Cependant, il est possible qu'à des fins d'optimisation, la bibliothèque d'algèbre que nous utilisons implémente des modèles d'expression, et le type de retour réel est le suivant:

MultExpression<Matrix, Vector> operator* (const Matrix &lhs, const Vector &rhs);

Maintenant, le problème est que MultExpression<Matrix, Vector>, selon toute vraisemblance, stockera un const Matrix&et en const Vector&interne; il s'attend à ce qu'il se convertisse en a Vectoravant la fin de son expression complète. Si nous avons ce code, tout va bien:

extern Matrix a, b, c;
extern Vector v;

void compute()
{
  Vector res = a * (b * (c * v));
  // do something with res
}

Cependant, si nous avions utilisé autoici, nous pourrions avoir des ennuis:

void compute()
{
  auto res = a * (b * (c * v));
  // Oops! Now `res` is referring to temporaries (such as (c * v)) which no longer exist
}
Angew n'est plus fier de SO
la source
3
@NirFriedman Vous avez raison, c'est fort, mais je pense en fait que cela autoa très peu d'inconvénients, alors je m'en tiens à cette force. Et d'autres exemples de proxies, etc. incluent divers "générateurs de chaînes" et objets similaires trouvés dans les DSL.
Angew n'est plus fier de SO
2
J'ai été mordu par des modèles d'expression et autoavant, en particulier avec la bibliothèque Eigen. C'est particulièrement délicat car le problème n'apparaît souvent pas dans les versions de débogage.
Dan
1
L'utilisation de autopeut également mordre lors de l'utilisation de la bibliothèque de matrices Armadillo , qui utilise fortement la méta-programmation de modèles à des fins d'optimisation. Heureusement, les développeurs ont ajouté la fonction .eval () qui peut être utilisée pour éviter les problèmes avecauto
mtall
2
"Si vos interfaces sont clairement nommées, vous ne devriez pas avoir à vous soucier du type exact." Votre compilateur ne peut pas vérifier l'exactitude de votre code en étudiant les noms des variables. C'est le point entier d'un système de typage. Le contourner aveuglément est ridicule!
Courses de légèreté en orbite le
1
@Angew: Ce n'est pas un problème pour les temporaires car vous les utilisez généralement immédiatement, ce qui sans autoimpliquer généralement une sorte de vérification de type (et éclabousser autopartout enlève cette sécurité de type comme partout ailleurs). Ce n'est pas une bonne comparaison.
Courses de légèreté en orbite le
13

L'un des inconvénients est que parfois vous ne pouvez pas déclarer const_iteratoravec auto. Vous obtiendrez un itérateur ordinaire (non const) dans cet exemple de code tiré de cette question :

map<string,int> usa;
//...init usa
auto city_it = usa.find("New York");
ks1322
la source
3
Eh bien, vous obtenez un iteratordans tous les cas puisque votre carte n'est pas const. si vous voulez le convertir en a const_iterator, spécifiez explicitement le type de variable comme d'habitude, ou extrayez une méthode de sorte que votre map soit const dans le contexte de votre find. (Je préférerais ce dernier. SRP.)
Laurent LA RIZZA
auto city_it = static_cast<const auto&>(map).find("New York")? ou, avec C ++ 17 auto city_if = std::as_const(map).find("New York").
Dev Null
11

Cela rend votre code un peu plus difficile ou fastidieux à lire. Imaginez quelque chose comme ça:

auto output = doSomethingWithData(variables);

Maintenant, pour déterminer le type de sortie, vous devez rechercher la signature de la doSomethingWithDatafonction.

Skam
la source
40
Pas toujours. auto it = vec.begin();est beaucoup plus facile à lire que std::vector<std::wstring>::iterator it = vec.begin();par exemple.
Jonathan Potter
4
D'accord. Cela dépend du cas d'utilisation. J'aurais pu être plus précis à ce sujet.
Skam
1
@SeeDart ouais, les gens qui utilisent l'auto comme ça le font mal.
lciamp
6
«Traquer la signature de la fonction», si ce n'est pas un survol de la souris ou un appui sur une touche («suivre le symbole» / «aller à la déclaration» / quel que soit son nom), vous devez soit configurer davantage votre éditeur, soit passer à un IDE qui peut le faire sans configuration ... Votre point est toujours valide, cependant.
hyde
6
J'ai remarqué que pas dans un IDE mais dans de petits judas de diffs lors de l'examen des enregistrements! Avec l'auto, ils sont plus difficiles à lire pour cette raison.
JDługosz
10

Comme ce développeur, je déteste auto. Ou plutôt, je déteste la façon dont les gens abusentauto .

Je suis d'avis (fort) que autoc'est pour vous aider à écrire du code générique, pas pour réduire la frappe .
C ++ est un langage dont le but est de vous permettre d'écrire du code robuste, pas de minimiser le temps de développement.
Ceci est assez évident à partir de nombreuses fonctionnalités de C ++, mais malheureusement quelques-unes des plus récentes commeauto celle-ci réduisent la saisie en erreur en leur faisant croire qu'elles devraient commencer à être paresseuses avec la frappe.

Auparavant auto, les gens utilisaient typedefs, ce qui était génial parce que cela typedef permettait au concepteur de la bibliothèque de vous aider à déterminer quel devrait être le type de retour, afin que leur bibliothèque fonctionne comme prévu. Lorsque vous utilisez auto, vous enlevez ce contrôle au concepteur de la classe et demandez à la place au compilateur de déterminer quel doit être le type, ce qui supprime l'un des outils C ++ les plus puissants de la boîte à outils et risque de casser son code.

En général, si vous utilisez auto, cela devrait être parce que votre code fonctionne pour n'importe quel type raisonnable , pas parce que vous êtes simplement trop paresseux pour écrire le type avec lequel il devrait fonctionner. Si vous utilisez autocomme outil pour aider à la paresse, alors ce qui se passe, c'est que vous commencez finalement à introduire des bogues subtils dans votre programme, généralement causés par des conversions implicites qui ne se sont pas produites parce que vous avez utilisé auto.

Malheureusement, ces bogues sont difficiles à illustrer dans un court exemple ici parce que leur brièveté les rend moins convaincants que les exemples réels qui surviennent dans un projet utilisateur - cependant, ils se produisent facilement dans un code lourd en modèle qui s'attend à certaines conversions implicites. prennent endroit.

Si vous voulez un exemple, il y en a un ici . Une petite note cependant: avant d'être tenté de sauter et de critiquer le code: gardez à l'esprit que de nombreuses bibliothèques bien connues et matures ont été développées autour de telles conversions implicites, et elles sont là parce qu'elles résolvent des problèmes qui peuvent être difficiles voire impossibles à résoudre autrement. Essayez de trouver une meilleure solution avant de les critiquer.

user541686
la source
3
which was great because typedef allowed the designer of the library to help you figure out what the return type should be, so that their library works as expected. When you use auto, you take away that control from the class's designer and instead ask the compiler to figure out what the type should bePas vraiment une bonne raison IMO. Les IDE à jour, Visual Studio 2015 par exemple, vous permettent de vérifier le type de la variable en survolant auto. C'est * exactement * le même que celui- typedeflà.
Poulet Sombrero du
@JameyD: Il vous manque plusieurs points cruciaux: (1) Votre argument IDE ne fonctionne que si le type est concret et non basé sur un modèle. Les IDE ne peuvent pas vous indiquer le type correct dans le cas de types dépendants, par exemple typename std::iterator_traits<It>::value_type. (2) Le point essentiel était que le type inféré n'était pas nécessairement "exactement le même" que le type correct prévu par le concepteur précédent du code; en utilisant auto, vous enlevez la capacité du concepteur à spécifier le type correct.
user541686
Vous parlez essentiellement de procurations, que l'une des réponses mentionne déjà. Les modèles d'expression et les absurdités vectorielles <bool> ne sont pas du code courant pour la plupart des gens. Dans la plupart des situations, vous ne voulez pas de conversions implicites, et la fonction automatique y contribue. Herb Sutter parle longuement des avantages de l'automobile dans l'un de ses articles de blog, et il ne s'agit pas principalement de frappes au clavier, ni de code générique. De plus, le premier lien que vous avez fourni, le billet de blog est tout simplement un conseil terrible (c'est pourquoi il est critiqué avec véhémence dans sa section commentaires).
Nir Friedman le
@NirFriedman: "... vector<bool>non-sens" ... pardon? Comment pensez-vous qu'il bitsetest mis en œuvre? Ou considérez-vous que les conteneurs de bits sont complètement absurdes?!
user541686
1
@NirFriedman: Rien sur le vecteur <bool> n'est nouveau pour moi. Ce que j'essaie de vous dire et que vous refusez ouvertement de comprendre, c'est que pour les besoins de cette question, l'ensemble de bits n'est pas différent du vecteur <bool> - les deux utilisent des proxies, car les proxies ont été jugés utiles , et le fait que les procurations soient utiles est une réalité que vous devez accepter au lieu de vivre dans le déni. Pouvez-vous arrêter de transformer cela en un débat sur la question de savoir si vous pensez que les procurations sont utiles? Ce n'est pas le sujet du débat, et aussi, votre opinion à leur sujet n'est que votre opinion, pas une sorte de fait.
user541686
6

auton'a pas d'inconvénients en soi , et je recommande de l'utiliser (à la main) partout dans le nouveau code. Il permet à votre code de vérifier systématiquement le type et d'éviter systématiquement le découpage silencieux. (Si Bdérive de Aet qu'une fonction retournant Asoudainement retourne B, alorsauto se comporte comme prévu pour stocker sa valeur de retour)

Cependant, le code hérité pré-C ++ 11 peut s'appuyer sur des conversions implicites induites par l'utilisation de variables explicitement typées. Changer une variable explicitement typée en autopeut changer le comportement du code , vous feriez donc mieux d'être prudent.

Laurent LA RIZZA
la source
Le vote négatif est juste, mais pouvez-vous expliquer pourquoi?
Laurent LA RIZZA
Je ne vous ai pas critiqué, mais autoil y a des inconvénients en soi (ou du moins - beaucoup le pensent). Prenons l'exemple donné dans la deuxième question de cette table ronde avec Sutter, Alexandrescu et Meyers: si vous avez auto x = foo(); if (x) { bar(); } else { baz(); }et foo()retourne bool- que se passe-t-il si foo()change pour renvoyer une énumération (trois options au lieu de deux)? Le autocode continuera à fonctionner, mais produira des résultats inattendus.
einpoklum
@einpoklum: Et est-ce que l'utilisation boolau lieu de autochanger quoi que ce soit en cas d'énumération sans portée? Je me trompe peut-être (je ne peux pas vérifier ici), mais je pense que la seule différence est que la conversion se boolproduit lors de la déclaration de variable au lieu de l'évaluation de la condition dans le fichier if. Si le enumest défini, la conversion en boolne doit pas avoir lieu sans préavis explicite.
Laurent LA RIZZA
4

Le mot-clé autodéduit simplement le type de la valeur de retour. Par conséquent, ce n'est pas équivalent avec un objet Python, par exemple

# Python
a
a = 10       # OK
a = "10"     # OK
a = ClassA() # OK

// C++
auto a;      // Unable to deduce variable a
auto a = 10; // OK
a = "10";    // Value of const char* can't be assigned to int
a = ClassA{} // Value of ClassA can't be assigned to int
a = 10.0;    // OK, implicit casting warning

Comme il autoest déduit lors de la compilation, il n'aura aucun inconvénient à l'exécution.

Leben Asa
la source
1
oui, il fait essentiellement ce que fait type()en python. Il en déduit le type, il ne crée pas de nouvelle variable de ce type.
lciamp
2
@lciamp En fait, ce serait decltype. autoest pour l'affectation de variables spécifiquement.
2016 cubique
4

Ce que personne n'a mentionné ici jusqu'à présent, mais en soi, vaut une réponse si vous me le demandez.

Depuis (même si tout le monde doit savoir que C != C++ ) le code écrit en C peut facilement être conçu pour fournir une base pour le code C ++ et donc être conçu sans trop d'effort pour être compatible C ++, cela pourrait être une exigence de conception.

Je connais certaines règles dont certaines constructions bien définies ne Csont pas valides C++et vice versa. Mais cela entraînerait simplement des exécutables cassés et la clause UB connue s'applique, ce qui est la plupart du temps remarqué par des boucles étranges entraînant des plantages ou autre (ou même peut rester non détecté, mais cela n'a pas d'importance ici).

Mais autoc'est la première fois 1 ce changement!

Imaginez que vous utilisiez auparavant autocomme spécificateur de classe de stockage et que vous transfériez le code. Il ne serait même pas nécessairement (selon la manière dont il était utilisé) "casser"; il pourrait en fait modifier silencieusement le comportement du programme.

C'est quelque chose qu'il faut garder à l'esprit.


1 Au moins la première fois que je suis au courant.

Dhein
la source
1
Vous obtiendrez de toute façon une erreur de compilation en essayant de compiler.
Poulet Sombrero du
@JameyD: Que ferait-il? pourquoi 2 situations de code valides avec des significations différentes se traduiraient-elles par une erreur?
dhein
8
Si vous comptez sur "aucun type n'implique int" en C, vous méritez toutes les mauvaises choses que vous en tirerez. Et si vous ne vous y fiez pas, utiliser autocomme spécificateur de classe de stockage avec un type vous donnera une belle erreur de compilation en C ++ (ce qui est une bonne chose dans ce cas).
Angew n'est plus fier de SO
1
@Angew et bien c'est le cas auquel je fais référence, ouais. Je ne fais pas ça. Mais c'est quelque chose qu'il faut au moins garder à l'esprit.
dhein
3

Une raison à laquelle je peux penser est que vous perdez l'occasion de contraindre la classe qui est renvoyée. Si votre fonction ou méthode a renvoyé un long 64 bits et que vous ne vouliez qu'un 32 entier non signé, vous perdez l'opportunité de contrôler cela.

kblansit
la source
1
Il y a static_cast, et IIRC, par exemple, Effective Modern C ++ de Meyers recommande même de l'utiliser pour spécifier le type de variable auto-typée.
hyde
2

Comme je l'ai décrit dans cette réponse, cela auto peut parfois entraîner des situations géniales auxquelles vous n'aviez pas l'intention. Vous devez dire explicitement auto&avoir un type de référence tout en faisant simplement autopouvoir créer un type de pointeur. Cela peut entraîner une confusion en omettant le spécificateur tous ensemble, ce qui entraîne une copie de la référence au lieu d'une référence réelle.

Poulet Sombrero
la source
2
Ce n'est pas génial. C'est ce que autofait, sans jamais déduire de référence ni de consttype. Pour une autoréférence, vous feriez mieux d'utiliser auto&&. (une référence universelle) Si le type n'est pas bon marché à copier ou possède une ressource, alors le type ne doit pas être copiable pour commencer.
Laurent LA RIZZA
1

Un autre exemple irritant:

for (auto i = 0; i < s.size(); ++i)

génère un avertissement ( comparison between signed and unsigned integer expressions [-Wsign-compare]), car iest un entier signé. Pour éviter cela, vous devez écrire par exemple

for (auto i = 0U; i < s.size(); ++i)

ou peut-être mieux:

for (auto i = 0ULL; i < s.size(); ++i)
Paul R
la source
1
Oui, je trouve celui-ci aussi irritant. Mais le trou dans la langue est ailleurs. Pour que ce code soit vraiment portable, en supposant des sizeretours size_t, vous devez pouvoir avoir un size_tlittéral comme 0z. Mais vous pouvez déclarer un UDL pour ce faire. ( size_t operator""_z(...))
Laurent LA RIZZA
1
Objections purement théoriques: il unsignedest fort probable que ce ne soit pas assez grand pour contenir toutes les valeurs de std::size_tsur les architectures grand public, donc dans le cas peu probable où quelqu'un aurait un conteneur avec un nombre absurdement gigantesque d'éléments, l'utilisation unsignedpourrait provoquer une boucle infinie sur la plage inférieure d'indices. Bien que ce ne soit probablement pas un problème, il std::size_tdoit être utilisé pour obtenir un code propre qui signale correctement l'intention. Je ne suis pas sûr qu'il unsigned long longsoit strictement garanti que cela suffise, même si dans la pratique, cela doit probablement être le même.
underscore_d
@underscore_d: oui, juste point - unsigned long longest garanti au moins 64 bits, mais en théorie size_tpourrait être plus grand que cela, je suppose. Bien sûr, si vous avez> 2 ^ 64 éléments dans votre conteneur, vous pouvez avoir de plus gros problèmes à craindre ... ;-)
Paul R
1

Je pense que autoc'est bon lorsqu'il est utilisé dans un contexte localisé, où le lecteur peut facilement et évidemment déduire son type, ou bien documenté avec un commentaire de son type ou un nom qui en déduit le type réel. Ceux qui ne comprennent pas comment cela fonctionne pourraient le prendre de la mauvaise manière, comme l'utiliser à la place templateou similaire. Voici quelques bons et mauvais cas d'utilisation à mon avis.

void test (const int & a)
{
    // b is not const
    // b is not a reference

    auto b = a;

    // b type is decided by the compiler based on value of a
    // a is int
}

Bonnes utilisations

Itérateurs

std::vector<boost::tuple<ClassWithLongName1,std::vector<ClassWithLongName2>,int> v();

..

std::vector<boost::tuple<ClassWithLongName1,std::vector<ClassWithLongName2>,int>::iterator it = v.begin();

// VS

auto vi = v.begin();

Pointeurs de fonction

int test (ClassWithLongName1 a, ClassWithLongName2 b, int c)
{
    ..
}

..

int (*fp)(ClassWithLongName1, ClassWithLongName2, int) = test;

// VS

auto *f = test;

Mauvaises utilisations

Flux de données

auto input = "";

..

auto output = test(input);

Signature de fonction

auto test (auto a, auto b, auto c)
{
    ..
}

Cas triviaux

for(auto i = 0; i < 100; i++)
{
    ..
}
Khaled.K
la source
Lorsque vous voulez un int, vous devez taper un autre caractère si vous optez pour auto. C'est inacceptable
Rerito
@Rerito oui, c'est intaussi facile à voir ici et la frappe intest plus courte. C'est pourquoi c'est un cas trivial.
Khaled.K
0

Je suis surpris que personne n'ait mentionné cela, mais supposons que vous calculiez la factorielle de quelque chose:

#include <iostream>
using namespace std;

int main() {
    auto n = 40;
    auto factorial = 1;

    for(int i = 1; i <=n; ++i)
    {
        factorial *= i;
    }

    cout << "Factorial of " << n << " = " << factorial <<endl;   
    cout << "Size of factorial: " << sizeof(factorial) << endl; 
    return 0;
}

Ce code affichera ceci:

Factorial of 40 = 0
Size of factorial: 4

Ce n'était certainement pas le résultat escompté. C'est arrivé parce queauto déduit le type de la variable factorielle comme intparce qu'elle était affectée 1.

xilpex
la source