2017-01-29 6 views
0

Désistement: Je suis nouveau à C++.std :: unordered_set type de retour par référence vs valeur

J'ai un bloc de code comme ceci:

using BucketType = std::unordered_set<Bucket, BucketHash, BucketEqual>; 

    const BucketType& Range::buckets(int64_t value) { 
    BucketType buckets; 
    ... 
    return std::move(buckets); 
    } 

L'appelant appelle ce code comme ceci:

Range range; 
    auto buckets = range.buckets(11); 

Problème:

Quand je retourne la référence des seaux comme le code ci-dessus, le buckets.size() donne 140732261909672 cependant, j'ajoute seulement 2 seaux dans ma logique actuelle. Quand je change le code pour renvoyer la valeur au lieu de la référence, cela fonctionne parfaitement bien.

Des pointeurs sur ce qui pourrait ne pas fonctionner avec ce code?

+0

Essayez de retirer le & de la renvoie le type de 'buckets'. –

+2

N'utilisez pas 'std :: move' pour renvoyer une valeur à moins que ce ne soit le cas rare où c'est vraiment mieux. Non seulement les valeurs de retour seront-elles déplacées si possible, mais l'utilisation de 'std :: move' empêche en fait le résultat encore meilleur de (N) RVO. Maintenant, cela s'applique généralement pour les retours par valeur plutôt que par référence. Je ne suis pas sûr de ce que votre comportement souhaité est pour cette valeur de retour. – chris

+1

Version plus courte: N'utilisez pas ['std :: move'] (http://en.cppreference.com/w/cpp/utility/move) sauf si vous savez ce qu'il fait et comment l'utiliser. – WhozCraig

Répondre

1

Lets considérer votre buckets fonction:

const BucketType& Range::buckets(int64_t value) { 
    BucketType buckets; 
    ... 
    return std::move(buckets); 
} 

Ici vous créez un objet local du type BucketType, mouvement dans l'emplacement de la valeur de retour de la fonction, puis retour const référence lié à cette temporaire objet. Sans aucun doute, il conduit à comportement indéfini.

La bonne façon d'écrire une telle fonction est de simplifier le code et se débarrasser de const BucketType& et std::move(buckets):

BucketType Range::buckets(int64_t value) { 
    BucketType buckets; 
    ... 
    return buckets; 
} 

Maintenant buckets devient disponible pour le NRVO (du nom d'optimisation de la valeur de retour). Cela signifie que tous les compilateurs modernes exécutent copie élision ici et construire des objets BucketType directement (sans créer objet temporaire à l'emplacement de la valeur de retour de la fonction) quand ils sont initialisés avec buckets fonction:

auto buckets = range.buckets(11); // No unnecessary copies here 
+0

Si vous déposez le 'const' l'objet de retour, la came de retour sera déplacée, si pour une raison quelconque la copie ne peut pas être élidée (impossible de garantir l'élision sans savoir ce que le' ... 'signifie.) – juanchopanza

+0

@juanchopanza Oui définitivement! –