Auto C ++ et vs auto

88

Lors de la création de variables locales, est-il correct d'utiliser (const) auto&ou auto?

par exemple:

SomeClass object;
const auto result = object.SomeMethod();

ou const auto& result = object.SomeMethod();

Où SomeMethod () renvoie une valeur non primitive - peut-être un autre type défini par l'utilisateur. Ma compréhension est que const auto& resultc'est correct puisque le résultat retourné par SomeMethod () appellerait le constructeur de copie pour le type retourné. S'il vous plait corrigez moi si je me trompe.

Qu'en est-il des types primitifs? Je suppose que const auto sum = 1 + 2;c'est correct.

Cela s'applique-t-il également aux boucles basées sur la plage?

for(const auto& object : objects)
rohunb
la source
1
Je vous recommande vivement de lire ceci: safaribooksonline.com/library/view/effective-modern-c/… Les deux premiers chapitres sont gratuits et décrivent la déduction de type de modèle, qui est essentiellement comment autofonctionne (sauf pour le cas particulier de initializer_lists, qui sont non déduit dans un contexte de modèle), puis autotapez déduction.
vsoftco

Réponses:

102

autoet auto &&couvrent la plupart des cas:

  • À utiliser autolorsque vous avez besoin d'une copie locale. Cela ne produira jamais de référence. Le constructeur de copie (ou de déplacement) doit exister, mais il peut ne pas être appelé, en raison de l' optimisation d' élision de copie .

  • À utiliser auto &&lorsque vous ne vous souciez pas de savoir si l'objet est local ou non. Techniquement, cela produira toujours une référence, mais si l'initialiseur est temporaire (par exemple, la fonction retourne par valeur), il se comportera essentiellement comme votre propre objet local.

    De plus, auto &&ne garantit pas non plus que l'objet sera modifiable. Étant donné un constobjet ou une référence, il en déduira const. Cependant, la modifiabilité est souvent supposée, compte tenu du contexte spécifique.

auto &et auto const &sont un peu plus précis:

  • auto &garantit que vous partagez la variable avec autre chose. C'est toujours une référence et jamais un temporaire.

  • auto const &est comme auto &&, mais fournit un accès en lecture seule.

Qu'en est-il des types primitifs / non primitifs?

Il n'y a pas de différence.

Cela s'applique-t-il également aux boucles basées sur la plage?

Oui. Appliquer les principes ci-dessus,

  • À utiliser auto &&pour la possibilité de modifier et d'annuler les valeurs de la séquence dans la boucle. (Autrement dit, à moins que le conteneur ne fournisse une vue en lecture seule, par exemple std::initializer_list, auquel cas ce sera effectivement un auto const &.)
  • Utilisez auto &pour modifier les valeurs de la séquence de manière significative.
  • À utiliser auto const &pour un accès en lecture seule.
  • Utilisez autopour travailler avec des copies (modifiables).

Vous mentionnez également auto constsans référence. Cela fonctionne, mais ce n'est pas très couramment utilisé car il y a rarement un avantage à accéder en lecture seule à quelque chose que vous possédez déjà.

Potatoswatter
la source
Sutter dit que l'auto et les pistes constness
Jesse Pepper
1
@JessePepper Oui. (C'est un peu étrange de faire appel à l'autorité cependant.) Faites-vous référence à une partie spécifique de ceci?
Potatoswatter
En substance, cela auto&semble être un bon choix. Mais à utiliser const auto&lorsque vous souhaitez ajouter une constness qui n'est pas déjà là. auto&&est pour le transfert, ce qui, je pense, arrive plus souvent que Sutter ne le pense. Par exemple, vous voudrez peut-être stocker une valeur de retour par auto&&, puis la «transférer» vers deux choses, comme std :: cout pour voir la valeur pour le débogage et la transmettre également à une autre fonction. J'utilisais plus souvent l'auto &&, mais j'ai été mordu une ou deux fois par des choses inattendues. J'aurais aimé faire plus attention à ce qui n'a pas fonctionné!
Jesse Pepper
@JessePepper Oui, auto&&est lié à une fonctionnalité de langage manquante, qui devrait permettre de diviser toute instruction en instructions plus petites. La partie manquante est l'extension de la durée de vie ... J'ai mis pas mal d'efforts pour résoudre ce problème mais personne ne l'a remarqué. Ne mettez pas trop de stock dans le punditry :)
Potatoswatter
Sur auto const: Il peut être plus naturel d'écrire auto const x = fn (); si vous savez que la fonction ne renvoie pas de référence et que vous voulez que l'objet x ne change pas, pour éviter les bogues, ou le document qu'il utilise dans la portée. De la même manière que vous n'écririez pas normalement: const int & x = 1; Mais auto const & donne des résultats équivalents en raison des règles d'extension de durée de vie pour les références déclarées de cette manière.
Spacen Jasset
47

Oui, il est correct d'utiliser autoet auto&pour les variables locales. Lors de l'obtention du type de retour d'une fonction, il est également correct de l'utiliser auto&. Cela s'applique également aux boucles basées sur la plage.

Les règles générales d'utilisation autosont:

  • Choisissez auto xquand vous souhaitez travailler avec des copies.
  • Choisissez auto &xquand vous voulez travailler avec des éléments originaux et pouvez les modifier.
  • Choisissez auto const &xquand vous souhaitez travailler avec des éléments originaux et ne les modifierez pas.

Vous pouvez en savoir plus sur le spécificateur automatique ici .

fantôme
la source
9

autoutilise le même mécanisme de déduction de type que les modèles, la seule exception que je sache étant celle des listes brace-init, qui sont déduites par autoas std::initializer_list, mais non déduites dans un contexte de modèle.

auto x = expression;

fonctionne en supprimant d'abord tous les qualificatifs de référence et cv du type de l'expression de droite, puis en faisant correspondre le type. Par exemple, si vous avez const int& f(){...}alors auto x = f();déduit xcomme int, et non const int& .

L'autre forme,

auto& x = expression

ne supprime pas les qualificatifs cv, donc, en utilisant l'exemple ci-dessus, auto& x = f()déduit xcomme const int&. Les autres combinaisons ajoutent simplement des qualificatifs cv.

Si vous voulez que votre type soit toujours déduit avec des qualificatifs cv-ref, utilisez le tristement célèbre decltype(auto)en C ++ 14, qui utilise les decltyperègles de déduction de type.

Donc, en un mot, si vous voulez des copies, utilisez auto, si vous voulez des références, utilisez auto&. À utiliser constchaque fois que vous voulez une const-ness supplémentaire .


EDIT Il existe un cas d'utilisation supplémentaire,

auto&& x = expression;

qui utilise les règles de réduction des références, comme dans le cas de la transmission des références dans le code du modèle. Si expressionest une lvalue, alors xest une référence lvalue avec les qualificatifs cv de expression. Si expressionest une rvalue, alors xest une référence rvalue.

vsoftco
la source
@Potatoswatter Merci, édité. Je m'interroge en fait sur le cv pour rvalues. Existe-t-il un moyen simple de tester? Et comment pouvez-vous avoir une rvalue qualifiée cv? Lors du retour de la fonction, le cv est ignoré.
vsoftco
Non, il n'est pas ignoré lors des retours de fonction. Il est écarté pour les prvalues ​​de tous les types scalaires (C ++ 14 [et autres éditions] §5 / 6). Vous pouvez en obtenir un en utilisant un appel de fonction ou une notation cast. Les valeurs x qualifiées par CV fonctionnent de la même manière que toute autre chose: auto && x = std::move< const int >( 5 );déclarera int const && x, bien qu'elles soient rarement utilisées.
Potatoswatter
@Potatoswatter merci, vous avez raison, mon erreur. J'ai d'abord testé avec des POD, auquel cas le cv est jeté, et j'ai pensé que c'était le cas général. Bien sûr, il ne devrait pas être écarté, car en général, on peut vouloir conserver le cv (par exemple, pour ne pas appeler une fonction membre non-const sur les retours de rvalue).
vsoftco
Ignoré pour les types scalaires. Les POD peuvent être des classes. Quoi qu'il en soit, c'est un coin hackish de l'intersection du modèle d'expression et du modèle objet.
Potatoswatter
2

Lors de la création de variables locales, est-il correct d'utiliser (const) auto & ou auto?

Oui. L'auto n'est rien d'autre qu'un type déduit du compilateur, utilisez donc des références là où vous utiliseriez normalement des références et des copies locales (automatiques) là où vous utiliseriez normalement des copies locales. L'utilisation ou non d'une référence est indépendante de la déduction de type.

Où SomeMethod () renvoie une valeur non primitive - peut-être un autre type défini par l'utilisateur. Je crois comprendre que const auto & result est correct puisque le résultat retourné par SomeMethod () appellerait le constructeur de copie pour le type retourné. S'il vous plait corrigez moi si je me trompe.

Légal? Oui, avec le const. Meilleur entrainement? Probablement pas, non. Du moins, pas avec C ++ 11. Surtout pas, si la valeur renvoyée par SomeMethod () est déjà temporaire. Vous voudrez en savoir plus sur la sémantique de déplacement C ++ 11, l'élision de copie et l'optimisation de la valeur de retour: https://juanchopanzacpp.wordpress.com/2014/05/11/want-speed-dont-always-pass-by- valeur/

http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=199

https://isocpp.org/wiki/faq/ctors#return-by-value-optimization

Qu'en est-il des types primitifs? Je suppose que const auto sum = 1 + 2; est correct.

Oui, c'est bien.

Cela s'applique-t-il également aux boucles basées sur la plage?

for (const auto & object: objets)

Oui, c'est bien aussi. J'écris ce genre de code au travail tout le temps.

tweej
la source