140 votes

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

un 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, comparé à d' 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?

114voto

Howard Hinnant Points 59526

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:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    for (auto& e : v)
        e = true;
}

Cela ne veut pas compiler, car rvalue vector<bool>::reference retourné à partir de l' iterator ne se lient pas à un non-const lvalue de référence. Mais cela va fonctionner:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    for (auto&& e : v)
        e = true;
}

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 ferais pas cela gratuitement, car il ne veut 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 pour expliquer pourquoi:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    // using auto&& so that I can handle the rvalue reference
    //   returned for the vector<bool> case
    for (auto&& e : v)
        e = true;
}

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, alors auto serait de travailler ainsi que l' auto&&. Mais lorsque la boucle a été parfois traiter les non-proxy références et parfois proxy-références, je pense qu' auto&& qui allait devenir la solution de choix.

28voto

Dietmar Kühl Points 70604

À l'aide de auto&& ou des références universelles avec une gamme à base for-boucle a l'avantage que vous rend ce que vous obtenez. Pour la plupart des types d'itérateurs vous aurez probablement obtenir soit une T& ou T const& pour certains type T. 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 transfert std::for_each():

template <typename InIt, typename F>
F std::for_each(InIt it, InIt end, F f) {
    for (; it != end; ++it) {
        f(*it); // <---------------------- here
    }
    return f;
}

La fonction de l'objet f peut traiter T&, T const&, et T différemment. Pourquoi le corps d'une gamme à base for-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:

for (auto&& x: range) {
    f(std::forward<decltype(x)>(x));
}

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.

8voto

Puppy Points 90818

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 utilisez auto&& x, alors vous savez qu' x est exactement *it, à chaque fois.

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