populares hashtags c++ stl swap

c++ - populares - hashtags facebook 2018



Beneficios de una funciĆ³n de intercambio? (7)

Eficiencia:

Si tiene una clase que contiene punteros (inteligentes) a datos, es probable que sea más rápido intercambiar los punteros que intercambiar los datos reales: 3 copias de puntero frente a 3 copias en profundidad.

Si usa ''usar std :: swap'' + una llamada no calificada para intercambiar (o simplemente una llamada calificada para boost :: swap), ADL seleccionará la función de intercambio personalizada, permitiendo que se escriba un código de plantilla eficiente.

La seguridad:

Los intercambios de punteros (punteros sin formato, std :: auto_ptr y std :: tr1 :: shared_ptr) no se lanzan, por lo que se pueden usar para implementar un intercambio no lanzable. Un intercambio no lanzable facilita la escritura de código que proporciona la garantía de excepción sólida (código transaccional).

El patrón general es:

class MyClass { //other members etc... void method() { MyClass finalState(*this);//copy the current class finalState.f1();//a series of funcion calls that can modify the internal finalState.f2();//state of finalState and/or throw. finalState.f3(); //this only gets call if no exception is thrown - so either the entire function //completes, or no change is made to the object''s state at all. swap(*this,finalState); } };

En cuanto a si debe implementarse como amigo; el intercambio generalmente requiere el conocimiento de los detalles de implementación. Es una cuestión de gusto si usar un no amigo que llama a una función miembro o usar un amigo.

Problemas:

Un intercambio personalizado suele ser más rápido que una asignación simple, pero una asignación única siempre es más rápido que el intercambio de tres asignaciones predeterminado. Si desea mover un objeto, es imposible saber de forma genérica si un intercambio o una asignación sería lo mejor, un problema que C ++ 0x resuelve con los constructores de movimientos.

Navegando a través de algunas preguntas de C ++, a menudo he visto comentarios de que una clase compatible con STL debería implementar una función de swap (generalmente como amigo). un friend ?


Interpreté tu pregunta básicamente como tres preguntas diferentes (relacionadas).

  1. ¿Por qué STL necesita intercambio?
  2. ¿Por qué debería implementarse un swap especializado (iso dependiendo del swap predeterminado)?
  3. ¿Por qué debería implementarse como un amigo?

¿Por qué STL necesita swap?

La razón por la que una clase compatible con STL necesita un swap es que el swap se utiliza como una operación primitiva en muchos algoritmos STL. (p. ej., reverse , sort , partition , etc. se implementan normalmente utilizando swap )

¿Por qué debería implementarse un swap especializado (iso dependiendo del swap predeterminado)?

Ya hay muchas (buenas) respuestas a esta parte de su pregunta. Básicamente, conocer los aspectos internos de una clase con frecuencia le permite escribir una función de swap mucho más optimizada.

¿Por qué debería implementarse como un amigo?

Los algoritmos STL siempre llamarán swap como una función gratuita. Por lo tanto, debe estar disponible como una función no miembro para que sea útil.
Y, ya que solo es beneficioso escribir un intercambio personalizado cuando puede usar el conocimiento de las estructuras internas para escribir un intercambio mucho más eficiente, esto significa que su función gratuita necesitará acceso a los aspectos internos de su clase, por lo tanto, un amigo.

Básicamente, no tiene que ser un amigo, pero si no necesita ser un amigo, por lo general tampoco hay razón para implementar un intercambio personalizado.

Tenga en cuenta que debe asegurarse de que la función gratuita esté dentro del mismo espacio de nombres que su clase, de modo que los algoritmos STL puedan encontrar su función gratuita mediante la búsqueda de Koening.


La versión estándar de std :: swap () funcionará para la mayoría de los tipos que son asignables.

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

Pero no es una implementación óptima, ya que realiza una llamada al constructor de copia seguido de dos llamadas al operador de asignación.

Al agregar su propia versión de std :: swap () para su clase, puede implementar una versión optimizada de swap ().

Por ejemplo std :: vector. La implementación predeterminada como se definió anteriormente sería muy costosa, ya que necesitaría hacer una copia de toda el área de datos. Liberar potencialmente áreas de datos antiguas o reasignar el área de datos, así como invocar el constructor de copia para el tipo contenido en cada elemento copiado. Una versión especializada tiene una forma muy simple y sencilla de hacer 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); }

Como resultado, si su clase puede optimizar la operación swap (), probablemente debería hacerlo. De lo contrario se utilizará la versión por defecto.

Personalmente, me gusta implementar swap () como un método de miembro no lanzador. Luego proporcione una versión especializada 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); }



Para implementar operadores de asignación:

class C { C(C const&); void swap(C&) throw(); C& operator=(C x) { this->swap(x); return *this; } };

Esta es una excepción segura, la copia se realiza a través del constructor de copia cuando se pasa por valor, y el compilador puede optimizar la copia cuando pasa un temporal (mediante elisión de copia ).


Para la mayoría de las clases, el intercambio predeterminado está bien, sin embargo, el intercambio predeterminado no es óptimo en todos los casos. El ejemplo más común de esto sería una clase que utiliza la expresión Pointer to Implementation . Donde, como con el intercambio predeterminado, se copiaría una gran cantidad de memoria, es un intercambio especializado, se podría acelerar significativamente intercambiando solo los punteros.

Si es posible, no debería ser un amigo de la clase; sin embargo, es posible que deba acceder a datos privados (por ejemplo, los punteros sin procesar) que su clase probablemente no desee exponer en la clase API.


Si desea intercambiar (por ejemplo) dos vectores sin saber nada sobre su implementación, básicamente tiene que hacer algo como esto:

typedef std::vector<int> vec; void myswap(vec &a, vec &b) { vec tmp = a; a = b; b = tmp; }

Esto no es eficiente si a y b contienen muchos elementos ya que todos esos elementos se copian entre a , b y tmp .

Pero si la función de intercambio conociera y tuviera acceso a las partes internas del vector, podría haber una implementación más eficiente posible:

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; // ... }

En esta implementación solo se deben copiar algunos indicadores, no todos los elementos como en la primera versión. Y como esta implementación necesita acceso a las partes internas del vector, tiene que ser una función amiga.