31 votes

Avantages d'une fonction de swap?

En parcourant certaines questions C ++, j'ai souvent vu des commentaires selon lesquels une classe compatible STL devrait implémenter une fonction swap (généralement en tant qu'ami). Quelqu'un peut-il expliquer quels avantages cela apporte, comment la STL s'intègre à cela et pourquoi cette fonction doit être implémentée en friend ?

25voto

Yacoby Points 29771

Pour la plupart des classes, la valeur par défaut swap est très bien, cependant, le défaut de swap n'est pas optimal dans tous les cas. L'exemple le plus commun de ce qui serait une classe à l'aide du Pointeur de la mise en Œuvre de l'idiome. Si le contrat d'échange sur défaut d'une grande quantité de mémoire serait d'avoir copié, c'est que vous spécialisé swap, vous pouvez l'accélérer de façon significative par la seule permutation des pointeurs.

Si possible, il ne devrait pas être un ami de la classe, mais il peut avoir besoin d'accéder à des données privées (par exemple, la crue des pointeurs) qui vous classe n'a probablement pas envie d'exposer dans la classe de l'API.

23voto

Loki Astari Points 116129

La version standard de std::swap() fonctionnera pour la plupart des types qui sont cessibles.

void std::swap(T& lhs,T& rhs)
{
    T tmp(lhs);
    lhs = rhs;
    rhs = tmp;
} 

Mais ce n'est pas une mise en œuvre optimale, car il fait un appel au constructeur de copie suivie par les deux appels à l'opérateur d'affectation.

En ajoutant votre propre version de std::swap() de votre classe, vous pouvez mettre en œuvre une version optimisée de swap().

Par exemple std::vector. L'implémentation par défaut tel que défini ci-dessus serait très coûteux que vous auriez besoin de faire une copie de l'ensemble de la zone de données. Potentiellement la libération des données anciennes zones ou de ré-allouer de la zone de données ainsi que d'invoquer le constructeur de copie pour les contenus de type sur chaque élément copié. Une version spéciale est très simple moyen facile de le faire std::swap()

// NOTE this is not real code.
// It is just an example to show how much more effecient swaping a vector could
// be. And how using a temporary for the vector object is not required.
std::swap(std::vector<T>& lhs,std::vector<T>& rhs)
{
    std::swap(lhs.data,rhs.data);  // swap a pointer to the data area
    std::swap(lhs.size,rhs.size);  // swap a couple of integers with size info.
    std::swap(lhs.resv,rhs.resv);
}

En conséquence, si votre classe peut optimiser le swap() de l'opération, alors vous devriez probablement faire. Sinon, la version par défaut sera utilisé.

Personnellement, j'aime à mettre en œuvre swap() non jetant un membre de méthode. Ensuite fournir une version spécialisée de std::swap():

class X
{
    public:
        // As a side Note:
        //    This is also useful for any non trivial class
        //    Allows the implementation of the assignment operator
        //    using the copy swap idiom.
        void swap(X& rhs) throw (); // No throw exception guarantee
};


  // Should be in the same namespace as X.
  // This will allows ADL to find the correct swap when used by objects/functions in
  // other namespaces.
  void swap(X& lhs,X& rhs)
  {
     lhs.swap(rhs);
  } 

17voto

sth Points 91594

Si vous voulez échanger (par exemple) deux vecteurs sans rien connaître de leur mise en œuvre, en gros, vous avez à faire quelque chose comme ceci:

typedef std::vector<int> vec;

void myswap(vec &a, vec &b) {
   vec tmp = a;
   a = b;
   b = tmp;
}

Ce n'est pas efficace si a et b contenir de nombreux éléments, puisque tous ces éléments sont copiés entre a, b et tmp.

Mais si la fonction d'échange permettrait de connaître et d'avoir accès à l'intérieur du vecteur, il pourrait y avoir une application plus efficace possible:

void std::swap(vec &a, vec &b) {
   // assuming the elements of the vector are actually stored in some memory area
   // pointed to by vec::data
   void *tmp = a.data;
   a.data = b.data;
   b.data = tmp;
   // ...
}

Dans cette mise à seulement quelques pointeurs doivent être copiés, pas tous les éléments comme dans la première version. Et depuis cette mise en œuvre a besoin d'accéder à l'intérieur du vecteur, il doit être un ami de la fonction.

10voto

Pieter Points 9200

J'ai interprété votre question essentiellement trois différentes (liées) questions.

  1. Pourquoi ne STL besoin de swap?
  2. Pourquoi devrait spécialisé swap être mis en place (j'.s.o. en s'appuyant sur la valeur par défaut swap)?
  3. Pourquoi devrait-il être mis en œuvre comme un ami?

Pourquoi ne STL besoin de swap?

La raison STL amical les besoins de la classe swap que swap est utilisé comme un primitif dans de nombreux algorithmes de la STL. (par exemple, reverse, sort, partition etc. sont généralement mis en œuvre à l'aide de swap)

Pourquoi devrait spécialisé swap être mis en place (j'.s.o. en s'appuyant sur la valeur par défaut swap)?

Il y a beaucoup de (bonnes) réponses à cette partie de votre question déjà. Fondamentalement, connaître le fonctionnement interne d'une classe fréquemment vous permet d'écrire un beaucoup plus optimisé swap fonction.

Pourquoi devrait-il être mis en œuvre comme un ami?

Les algorithmes de la STL sera toujours appeler swap comme une fonction libre. Il doit donc être disponible en fonction de membre pour être utile.
Et, puisque c'est seulement bénéfique pour écrire une personnalisation de l'échange lorsque vous pouvez utiliser la connaissance des structures internes pour écrire un beaucoup plus efficace de swap, cela signifie que votre fonction libre aura besoin d'accéder à l'intérieur de votre classe, donc un ami.

Fondamentalement, il ne veut pas avoir à être un ami, mais si elle n'a pas besoin d'être un ami, il n'y a généralement pas de raison de mettre en œuvre une coutume swap soit.

Notez que vous devez vous assurer que la fonction est à l'intérieur du même espace de noms que votre classe, afin que les algorithmes de la STL pouvez trouver votre fonction libre via Koening de recherche.

9voto

Igor Zevaka Points 32586

Une autre utilisation de la fonction d'échange est de faciliter le code d'exception: http://www.gotw.ca/gotw/059.htm

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