227 votes

L'utilisation de la fonction "auto" de C++11 peut-elle améliorer les performances ?

Je peux voir pourquoi le auto en C++11 améliore la correction et la maintenabilité. J'ai lu que cela pouvait également améliorer les performances ( Presque toujours Auto par Herb Sutter), mais il me manque une bonne explication.

  • Comment auto améliorer les performances ?
  • Quelqu'un peut-il donner un exemple ?

306voto

Barry Points 45207

auto peut contribuer aux performances en éviter les conversions implicites silencieuses . Un exemple que je trouve convaincant est le suivant.

std::map<Key, Val> m;
// ...

for (std::pair<Key, Val> const& item : m) {
    // do stuff
}

Vous voyez l'insecte ? Nous sommes là, pensant que nous prenons élégamment chaque élément de la carte par référence constante et que nous utilisons la nouvelle expression range-for pour rendre notre intention claire, mais en fait nous copions chaque élément. Cela est dû au fait que std::map<Key, Val>::value_type es std::pair<const Key, Val> pas std::pair<Key, Val> . Ainsi, lorsque nous avons (implicitement) :

std::pair<Key, Val> const& item = *iter;

Au lieu de prendre une référence à un objet existant et d'en rester là, nous devons effectuer une conversion de type. Vous êtes autorisé à prendre une référence const vers un objet (ou temporaire) d'un type différent tant qu'il existe une conversion implicite disponible, par ex :

int const& i = 2.0; // perfectly OK

La conversion de type est une conversion implicite autorisée pour la même raison que vous pouvez convertir un fichier const Key à un Key mais nous devons construire un temporaire du nouveau type afin de le permettre. Donc, effectivement, notre boucle fait :

std::pair<Key, Val> __tmp = *iter;       // construct a temporary of the correct type
std::pair<Key, Val> const& item = __tmp; // then, take a reference to it

(Bien sûr, il n'y a pas réellement de __tmp il est juste là pour l'illustration, en réalité le temporaire sans nom est juste lié à l'objet item pour sa durée de vie).

Je change juste pour :

for (auto const& item : m) {
    // do stuff
}

vient de nous épargner une tonne de copies - maintenant le type référencé correspond au type de l'initialisateur, donc aucun temporaire ou conversion n'est nécessaire, nous pouvons juste faire une référence directe.

69voto

Kerrek SB Points 194696

Parce que auto déduit le type de l'expression d'initialisation, il n'y a pas de conversion de type impliquée. Combiné avec les algorithmes modélisés, cela signifie que vous pouvez obtenir un calcul plus direct que si vous deviez inventer un type vous-même - surtout lorsque vous avez affaire à des expressions dont vous ne pouvez pas nommer le type !

Un exemple typique vient de (ab)utiliser std::function :

std::function<bool(T, T)> cmp1 = std::bind(f, _2, 10, _1);  // bad
auto cmp2 = std::bind(f, _2, 10, _1);                       // good
auto cmp3 = [](T a, T b){ return f(b, 10, a); };             // also good

std::stable_partition(begin(x), end(x), cmp?);

Avec cmp2 y cmp3 l'algorithme entier peut mettre en ligne l'appel de comparaison, tandis que si vous construisez un fichier std::function non seulement l'appel ne peut pas être inlined, mais vous devez également passer par la recherche polymorphe dans l'intérieur de l'enveloppe de la fonction.

Une autre variante de ce thème est que vous pouvez dire :

auto && f = MakeAThing();

Il s'agit toujours d'une référence, liée à la valeur de l'expression d'appel de fonction, et ne construit jamais d'objets supplémentaires. Si vous ne connaissiez pas le type de la valeur retournée, vous pourriez être forcé de construire un nouvel objet (peut-être de manière temporaire) via quelque chose comme T && f = MakeAThing() . (D'ailleurs, auto && fonctionne même lorsque le type de retour n'est pas mobile et que la valeur de retour est une prvalue).

41voto

Yakk Points 31636

Il existe deux catégories.

auto peut éviter l'effacement des types. Il existe des types innommables (comme les lambdas), et des types presque innommables (comme le résultat de std::bind ou d'autres éléments semblables à des modèles d'expression).

Sans auto vous finissez par devoir effacer les données jusqu'à quelque chose comme std::function . L'effacement des données a un coût.

std::function<void()> task1 = []{std::cout << "hello";};
auto task2 = []{std::cout << " world\n";};

task1 a une surcharge d'effacement de type -- une possible allocation de tas, une difficulté d'inlining, et une surcharge d'invocation de table de fonction virtuelle. task2 n'en a pas. Lambdas besoin de auto ou d'autres formes de déduction de type pour stocker sans effacement de type ; d'autres types peuvent être si complexes qu'ils n'en ont besoin qu'en pratique.

Deuxièmement, vous pouvez vous tromper de type. Dans certains cas, le mauvais type fonctionnera en apparence parfaitement, mais provoquera une copie.

Foo const& f = expression();

sera compilé si expression() renvoie à Bar const& o Bar donde Foo peut être construit à partir de Bar . Un temporaire Foo sera créé, puis lié à f et sa durée de vie sera prolongée jusqu'à f s'en va.

Le programmeur a peut-être voulu dire Bar const& f et non destiné à y faire une copie, mais une copie est quand même faite.

L'exemple le plus courant est le type de *std::map<A,B>::const_iterator qui est std::pair<A const, B> const& no std::pair<A,B> const& mais l'erreur est une catégorie d'erreurs qui coûtent silencieusement la performance. Vous pouvez construire un std::pair<A, B> d'un std::pair<const A, B> . (La clé sur une carte est const, parce que l'éditer est une mauvaise idée)

Tant @Barry que @KerrekSB ont d'abord illustré ces deux principes dans leurs réponses. Il s'agit simplement d'une tentative de mettre en évidence les deux questions dans une seule réponse, avec une formulation qui vise le problème plutôt que d'être centrée sur l'exemple.

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