103 votes

Le nouveau mot-clé "auto" ; quand doit-il être utilisé pour déclarer un type de variable ?

Duplicata possible :
Combien est trop avec le mot-clé C++0x auto ?

Avons-nous (en tant que communauté) suffisamment d'expérience pour déterminer quand et/ou si l'auto est abusée ?

Ce que je recherche vraiment, c'est un guide des meilleures pratiques en matière de

  • quand utiliser auto
  • quand il faut l'éviter

Des règles simples qui peuvent être rapidement suivies dans 80% des cas.

En guise de contexte, cette question est suscitée par ma réponse aquí

10 votes

Le mot-clé auto réduit à coup sûr la lisibilité du code.

1 votes

@OncleBens Je ne pense pas que cela soit mauvais du tout. L'argument du type de modèle pour static_cast indique immédiatement quel type m est, il est donc très lisible. IMO, l'abus est dans les cas où vous utilisez auto pour déduire les types de valeurs de retour des fonctions définies par l'utilisateur.

1 votes

@Praetorian Je ne suis pas d'accord, auto dans ces circonstances, réduit les conversions et les dépendances. S'il n'est pas important qu'une valeur ait une valeur particulier mais seulement qu'il a le bon type, alors utilisez auto Libéralement !

164voto

Nawaz Points 148870

Je pense que lorsque le type est très connu parmi les coprogrammeurs qui travaillent (ou travailleraient) dans votre projet, alors auto peut être utilisé, comme dans le code suivant :

//good : auto increases readability here
for(auto it = v.begin(); it != v.end(); ++it) //v is some [std] container
{
      //..
}

Ou, plus généralement,

//good : auto increases readability here
for(auto it = std::begin(v); it != std::end(v); ++it)//v could be array as well
{
      //..
}

Mais lorsque le type n'est pas très connu et peu utilisé, alors je pense que auto semble réduire la lisibilité, comme ici :

//bad : auto decreases readability here
auto obj = ProcessData(someVariables);

Alors que dans le premier cas, l'utilisation de auto semble très bon et ne réduit pas la lisibilité, et peut donc être utilisé de manière extensive, mais dans le dernier cas, il réduit la lisibilité et ne devrait donc pas être utilisé.


Un autre endroit où auto peut être utilisé est lorsque vous utilisez new 1 o make_* fonctions, comme ici :

//without auto. Not that good, looks cumbersome
SomeType<OtherType>::SomeOtherType * obj1 = new SomeType<OtherType>::SomeOtherType();
std::shared_ptr<XyzType> obj2 = std::make_shared<XyzType>(args...);
std::unique_ptr<XyzType> obj2 = std::make_unique<XyzType>(args...);

//With auto. good : auto increases readability here
auto obj1 = new SomeType<OtherType>::SomeOtherType();
auto obj2 = std::make_shared<XyzType>(args...);
auto obj3 = std::make_unique<XyzType>(args...);

Il s'agit ici d'une très bonne solution, car elle permet de réduire l'utilisation du clavier, sans pour autant réduire la lisibilité, puisque n'importe qui peut connaître le type d'information. objets en cours de création, juste en regardant le code.

1. Évitez d'utiliser <code>new</code> et les pointeurs bruts cependant.


Parfois, le type est si peu pertinent que la connaissance du type n'est même pas nécessaire, comme dans modèle d'expression ; en fait, pratiquement il est impossible d'écrire le type (correctement), dans de tels cas auto est un soulagement pour les programmeurs. J'ai écrit une bibliothèque de modèles d'expression qui peut être utilisée comme :

foam::composition::expression<int> x;

auto s = x * x;       //square
auto c = x * x * x;   //cube
for(int i = 0; i < 5 ; i++ )
    std::cout << s(i) << ", " << c(i) << std::endl; 

Sortie :

0, 0
1, 1
4, 8
9, 27
16, 64

Maintenant, comparez le code ci-dessus avec le suivant équivalent qui n'utilise pas auto :

foam::composition::expression<int> x;

//scroll horizontally to see the complete type!!
foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<int>, foam::composition::expression<int>, foam::operators::multiply>> s = x * x; //square
foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<int>, foam::composition::expression<int>, foam::operators::multiply> >, foam::composition::expression<int>, foam::operators::multiply>> c = x * x * x; //cube

for(int i = 0; i < 5 ; i++ )
    std::cout << s(i) << ", " << c(i) << std::endl; 

Comme vous pouvez le voir, dans de tels cas auto vous facilite la vie de manière exponentielle. Les expressions utilisées ci-dessus sont très simples ; réfléchissez au type de certaines expressions plus complexes :

auto a = x * x - 4 * x + 4; 
auto b = x * (x + 10) / ( x * x+ 12 );
auto c = (x ^ 4 + x ^ 3 + x ^ 2 + x + 100 ) / ( x ^ 2 + 10 );

Le type de telles expressions serait encore plus énorme et laid, mais grâce à auto nous pouvons maintenant laisser le compilateur déduire le type des expressions.


Donc l'essentiel est : le mot clé auto pourrait augmenter ou diminuer la clarté et la lisibilité de votre code, en fonction du contexte . Si le contexte indique clairement ce que type ou du moins comment il devrait être utilisé (dans le cas d'un itérateur de conteneur standard) ou que la connaissance du type réel n'est même pas nécessaire (comme dans les modèles d'expression), alors auto devrait être utilisé et si le contexte n'est pas clair et que ce n'est pas très courant (comme le deuxième cas ci-dessus), alors il vaut mieux que ce soit a évité .

1 votes

Dans votre premier exemple. je pense que je ne l'utiliserais que dans le contexte d'une boucle for. for(auto it = v.begin(); it != v.end(); ++it) {}

0 votes

@LokiAstari : Ajouté les exemples de modèles d'expression. Voyez-les :-)

2 votes

C'est le genre de réponses qui font stackoverflow ma première référence goto

21voto

spraff Points 10492

Facile. Utilisez-le lorsque vous je m'en fiche quel est le type. Par exemple

for (auto i : some_container) {
   ...

Tout ce qui m'importe ici, c'est que i est ce qui se trouve dans le conteneur.

C'est un peu comme les typedefs.

typedef float Height;
typedef double Weight;
//....
Height h;
Weight w;

Ici, je ne me soucie pas de savoir si h y w sont des flottants ou des doubles, mais seulement qu'ils sont quel que soit le type qui convient pour exprimer les hauteurs et les poids .

Ou encore

for (auto i = some_container .begin (); ...

Ici, tout ce qui m'importe, c'est qu'il s'agisse d'un itérateur approprié, supportant operator++() c'est un peu comme taper sur un canard à cet égard.

De plus, le type des lambdas ne peut pas être épelé, donc auto f = []... est un bon style. L'alternative est de couler à std::function mais cela entraîne des frais généraux.

Je ne peux pas vraiment concevoir un "abus" de auto . Le plus proche que je puisse imaginer est de vous priver d'une conversion explicite vers un type significatif -- mais vous n'utiliseriez pas auto Pour cela, il faut construire un objet du type souhaité.

Si vous puede supprimer une certaine redondance dans votre code sans introduire d'effets secondaires, alors cela debe Il est bon de le faire.

17voto

Konrad Rudolph Points 231505

J'appliquerais la même règle que pour var en C# : utilisez-le généreusement . Il s'agit de augmente la lisibilité. Sauf si le type d'une variable est suffisamment important pour être indiqué explicitement, auquel cas il faut le faire (duh).

Pourtant, je maintiens que (surtout dans les langages typés statiquement) le compilateur est bien meilleur que nous pour suivre les types. La plupart du temps, le exact Le type n'est pas terriblement important de toute façon (sinon les interfaces ne fonctionneraient pas en pratique). Il est plus important de savoir quelles opérations sont autorisées. Le contexte devrait nous le dire.

En outre, auto peut en fait prévenir les problèmes en évitant les conversions implicites non souhaitées dans les initialisations. En général, l'instruction Foo x = y; effectuera une conversion implicite si y n'est pas de type Foo et une conversion implicite existe. C'est la raison pour laquelle il faut éviter d'avoir des conversions implicites en premier lieu. Malheureusement, le C++ en a déjà beaucoup trop.

Rédaction auto x = y; permettra d'éviter ce problème en principe .

D'autre part, il devrait être clair que lorsque j'effectue des calculs qui supposent tel ou tel nombre d'octets dans un nombre entier, le type explicite de la variable doit être connu et doit être clairement indiqué.

Tous les cas ne sont pas aussi clairs, mais je maintiens que la plupart le sont, et que

  1. dans la plupart des cas, il est facile de voir si un type explicite doit être connu, et
  2. le besoin de types explicites est comparativement rare.

Eric Lippert développeur principal de l'équipe chargée du compilateur C#, a déclaré à peu près la même chose à propos de var .

2 votes

auto peut en fait prévenir les bogues, en empêchant les conversions implicites non souhaitées. -- Tout aussi facilement, cela peut introduire des bogues, lorsque des conversions implicites sont en fait recherché

7 votes

Je t'en prie, mais c'est tout simplement invraisemblable. Si vous veulent la conversion, vous l'utilisez. Si vous écrivez auto vous ne vous attendez clairement pas à ce qu'une conversion ait lieu.

0 votes

Konrad : ne trouvez-vous pas amusant que vous défendiez auto qui énonce implicitement l'intention de l'utilisateur pour éviter le danger des conversions implicites.

5voto

Jerry Coffin Points 237758

Je pense que la réponse à votre première question est en quelque sorte non. Nous en savons assez pour établir des lignes directrices sur quand utiliser ou éviter auto Mais il reste encore un certain nombre de cas pour lesquels le mieux que nous puissions dire actuellement est que nous ne pouvons pas encore donner beaucoup de conseils objectifs à leur sujet.

Le cas évident où vous avez presque ont pour l'utiliser est dans un modèle lorsque vous voulez (par exemple) le type approprié pour contenir le résultat d'une opération sur deux paramètres génériques. Dans un cas comme celui-ci, la seule possibilité d'abus ne serait pas vraiment l'abus de auto mais si le type général d'opération que vous effectuez (ou le type de modèle que vous écrivez, etc.) est quelque chose que vous feriez mieux d'éviter.

Il existe également au moins quelques situations où vous devez clairement éviter auto . Si vous utilisez quelque chose comme un type de proxy où vous dépendez de la conversion de proxy->cible pour faire une partie du travail à faire, auto va (tenter de) créer une cible du même type que la source afin que la conversion n'ait pas lieu. Dans certains cas, cela peut simplement retarder la conversion, mais dans d'autres, cela ne fonctionnera pas du tout (par exemple, si le type de proxy ne supporte pas l'affectation, ce qui est souvent le cas).

Un autre exemple serait le cas où vous devez vous assurer qu'une variable particulière a un type spécifique pour les besoins d'une interface externe, par exemple. Prenons l'exemple de l'application du masque réseau à une adresse IP (v4). Pour les besoins de l'argumentation, supposons que vous travaillez avec les différents octets de l'adresse (par exemple, en représentant chacun d'entre eux comme une variable de type unsigned char ), nous nous retrouvons donc avec quelque chose comme octets[0] & mask[0] . Grâce aux règles de promotion de type du C, même si les deux opérandes sont unsigned char le résultat sera généralement int . Nous besoin de le résultat doit être un unsigned char mais (c'est-à-dire un octet) pas un int (généralement 4 octets) cependant. Ainsi, dans cette situation, auto serait presque certainement inappropriée.

Dans de nombreux cas, il s'agit donc d'une question de jugement. Mon propre tendance pour ces cas est de traiter auto par défaut, et n'utiliser un type explicite que dans les cas qui ressemblent un tant soit peu au dernier cas que j'ai cité ci-dessus -- même si un type particulier n'est pas nécessaire pour un fonctionnement correct que j'ai vraiment veulent un type particulier, même si cela peut impliquer une conversion implicite.

Je pense (mais ce n'est qu'une supposition) qu'au fil du temps, je probablement tendent encore plus dans cette direction. Au fur et à mesure que je m'habituerai à ce que le compilateur choisisse les types, je découvrirai qu'un bon nombre de cas où j'ai actuellement le droit d'utiliser les types sont des cas de figure. piense en Je devrais spécifier le type, je n'en ai pas vraiment besoin et le code sera parfait.

Je soupçonne que beaucoup d'entre nous (et plus nous sommes âgés/expérimentés, plus nous serons mauvais à ce sujet) utiliseront des types explicites pour des raisons qui, en fin de compte, remontent à un sentiment sur les performances et à la conviction que notre choix améliorera les performances. Une partie du temps, nous puede même avoir raison - mais comme la plupart d'entre nous ayant une telle expérience l'ont constaté, nos suppositions sont souvent fausses (surtout lorsqu'elles sont basées sur des hypothèses implicites), et les compilateurs et les processeurs s'améliorent généralement dans ce domaine avec le temps.

0 votes

Cela semble très raisonnable. Je pense aussi que beaucoup d'entre nous (et plus nous sommes âgés/expérimentés) lorsque vous écrivez du code, sachez exactement les types que nous avons besoin d'utiliser (sauf les cas que vous avez spécifiés), donc l'utilisation de auto au lieu d'un type explicite demanderait dans certains cas plus de travail mental pour se prouver que c'est la même chose. Être explicite avec le compilateur n'est pas une mauvaise chose. Peut-être qu'avec le temps, ce fardeau d'utiliser auto disparaîtra.

0 votes

J'aime le fait que tu penses que les personnes âgées sont moins flexibles :-) Je me souviens quand nous sommes passés de < a != en faisant notre for(;;) des boucles pour s'adapter à ces majigies de nouveaux itérateurs. Nous avons tous dit "le monde s'effondrerait en décombres, avant que je ne passe à ce concept". Mais nous avons tous fini par y arriver :-) peut-être est-ce juste une autre de ces courbes d'apprentissage.

2voto

Will03uk Points 990

Ne l'utilisez qu'avec les types répétitifs longs tels que les modèles longs et les types de fonctions lambda. Essayez de l'éviter si vous le pouvez pour rendre les choses plus claires.

6 votes

Parce que la clarté serait horrible ! Pas vrai ? Non, laisse tomber. Utilisez pour plus de clarté.

0 votes

@Konrad Je veux dire éviter pour des raisons de clarté ; je ne dis pas éviter si cela rend les choses plus claires.

0 votes

@Will03uk "Éviter pour le bien de la clarté", signifie l'éviter s'il ne sert qu'à rendre les choses claires :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X