Quel est l'avantage d'utiliser des références universelles de gamme à base de boucles for?
const auto&
suffirait si je veux effectuer des opérations en lecture seule. Cependant, j'ai heurté
for (auto&& e : v) //v is non-const
une couple de fois récemment. Cela me fait me demander:
Est-il possible que dans quelque coin obscur cas, il est certain avantage en matière de performances en utilisant des références universelles, par rapport à auto&
ou const auto&
?
(shared_ptr
est un suspect pour coin obscur cas)
Mise à jour
Deux exemples que j'ai trouvé dans mes favoris:
Un désavantage de l'utilisation de const référence lors de l'itération sur les types de base?
Je peut facilement effectuer une itération sur les valeurs d'une carte à l'aide d'une gamme à base de boucle?
Merci de se concentrer sur la question: pourquoi voudrais-je utiliser l'auto&& dans la gamme à base de boucles for?
Je ne suis pas sûr qu'il y a assez contexte de votre question pour moi de mesurer le degré de "fou", il est où vous êtes le voir.
Longue histoire courte: pourquoi voudrais-je utiliser
auto&&
de gamme à base de boucles for?OriginalL'auteur Ali | 2012-10-29
Vous devez vous connecter pour publier un commentaire.
Le seul avantage que je peux voir, c'est quand la séquence renvoie un itérateur proxy de référence et vous avez besoin pour fonctionner sur cette référence non const. Par exemple, considérons:
Cela ne veut pas compiler, car rvalue
vector<bool>::reference
retourné à partir de laiterator
ne se lient pas à un non-const lvalue de référence. Mais cela va fonctionner:Tout cela étant dit, je n'aurais pas le code de cette façon, à moins que vous saviez que vous nécessaire pour satisfaire un tel cas d'utilisation. I. e. Je ne voudrais pas le faire gratuitement car il ne amener les gens à se demander ce que vous faites. Et si je l'ai fait faire, il ne serait pas mal d'ajouter un commentaire pourquoi:
Modifier
Ce dernier cas de la mine devrait vraiment être un modèle pour le sens. Si vous connaissez la boucle est toujours la manipulation d'un proxy de référence, puis
auto
fonctionnerait ainsi queauto&&
. Mais lorsque la boucle a été parfois traiter les non-proxy références et parfois proxy-références, alors je pense queauto&&
allait devenir la solution de choix.Un autre terme pour l'écriture de code inutilement confond personnes est: l'écriture confuscated code. Il est préférable de faire votre code aussi simple que possible, mais pas plus. Cela aidera à garder le nombre de bogues vers le bas. Cela étant dit, comme && devient plus familier, alors peut-être 5 ans à partir de maintenant, les gens s'attendent à une auto&& idiome (en supposant qu'il ne fait pas de mal). Je ne sais pas si ça va se produire ou non. Mais simple est dans l'œil de celui qui regarde, et si vous écrivez pour plus que juste vous-même, prenez vos lecteurs en compte.
Je préfère
const auto&
quand je veux le compilateur pour m'aider à vérifier que je n'ai pas modifier accidentellement les éléments dans la séquence.Personnellement, j'aime utiliser
auto&&
génériques de code où j'ai besoin de modifier les éléments de la séquence. Si je ne le fais pas, je vais juste coller àauto const&
.C'est grâce à des passionnés comme vous, constamment expérimenter et de faire pression pour de meilleures façons de faire les choses, que le C++ continue d'évoluer. Je vous remercie. 🙂
OriginalL'auteur Howard Hinnant
À l'aide de
auto&&
ou des références universelles avec une gamme à base defor
-boucle a l'avantage que vous rend ce que vous obtenez. Pour la plupart des types d'itérateurs vous aurez probablement obtenir unT&
ou unT const&
pour certains type deT
. Le cas intéressant est celui où le déréférencement d'un itérateur, les rendements temporaire: C++ 2011 suis détendue, les exigences et les itérateurs ne sont pas forcément nécessaires pour obtenir une lvalue. L'utilisation de références universelles correspond à l'argument de transfertstd::for_each()
:La fonction de l'objet
f
peut traiterT&
,T const&
, etT
différemment. Pourquoi le corps d'une gamme à base defor
-boucle serait-elle différente? Bien sûr, à prendre avantage d'avoir déduit le type à l'aide des références universelles vous auriez besoin de les transmettre en conséquence:Bien sûr, à l'aide de
std::forward()
signifie que vous acceptez toutes les valeurs renvoyées pour être déplacé. Si les objets comme cela fait beaucoup de sens dans le non-modèle de code je ne sais pas (encore?). Je peux imaginer que l'utilisation de références universelles peuvent offrir plus d'informations au compilateur de faire la bonne Chose. Dans basées sur des modèles de code, il reste en dehors de toute prise de décision sur ce qui doit se passer avec les objets.OriginalL'auteur Dietmar Kühl
J'utilise pratiquement toujours
auto&&
. Pourquoi se faire mordre par une arête cas lorsque vous n'avez pas à? C'est plus court à taper trop, et je ne le trouve plus... transparent. Lorsque vous utilisezauto&& x
, alors vous savez quex
est exactement*it
, à chaque fois.const
-ness avecauto&&
siconst auto&
suffit. La question demande le cas du coin où je peux obtenir mordu. Quels sont les cas du coin qui n'ont pas été mentionnés par Dietmar ou Howard encore?Voici une façon de se faire mordre si vous utiliser
auto&&
. Si le type de capture doivent être déplacés dans le corps de la boucle (par exemple), et est modifié à une date ultérieure si elle correspond à unconst&
type, votre code silencieusement continuer à fonctionner, mais vos mouvements seront venir des copies. Ce code va être très trompeur. Si, toutefois, vous spécifier explicitement le type comme une r-valeur de référence, celui qui a changé le type de conteneur obtiendrez une erreur de compilation car vous avez vraiment, vraiment envie de ces objets déplacés, et non pas copié...Je viens de tomber sur ceci: comment puis-je appliquer une référence rvalue sans spécifier explicitement le type? Quelque chose comme
for (std::decay_t<decltype(*v.begin())>&& e: v)
? Je pense qu'il y a une meilleure façon ...Cela dépend de ce que connaître le type. Comme mentionné ci-dessus,
auto&&
donnera un "univers de référence", donc rien d'autre que vous obtiendrez un plus spécifique. Siv
est supposé être unvector
, vous pourriez fairedecltype(v)::value_type&&
, qui est ce que je suppose que tu voulais en prenant le résultat deoperator*
sur un itérateur de type. Vous pouvez également faire dedecltype(begin(v))::value_type&&
pour vérifier l'itérateur de types plutôt que sur le contenant. Si nous avons si peu de perspicacité dans le type, bien, nous pourrions envisager un peu plus clair pour juste aller avecauto&&
...OriginalL'auteur Puppy