2011-05-27 14 views
5

que estaba poniendo en práctica (con fines de formación) una burbuja función Clasificar plantilla:¿Hay algún inconveniente obvio para usar un intercambio sin asignación?

template<typename iterInput, 
     typename predicate> 
void BubbleSort(iterInput first1,iterInput last1,predicate func) 
{ 
    bool swapped(false); 
    do 
    { 
     swapped = false; 
     iterInput begin = first1; 
     iterInput beginMinus = first1; 
     ++begin; 
     for (;begin != last1; begin++,beginMinus++) 
     { 
      if (func(*beginMinus,*begin)) 
      { 
       std::swap(*beginMinus,*begin); 
       swapped = true; 
      } 
     } 
    } 
    while(swapped); 
} 

Cuando me he dado cuenta de que esta función no funcionará para la clase con ningún operador de asignación, como éste (perdóname por la mala fama):

class NoCopyable 
{ 
public: 
    explicit NoCopyable(int value) : value_(value) {} 
    NoCopyable(const NoCopyable& other) : value_(other.value_) {} 
    ~NoCopyable() {} 
    bool operator<(const NoCopyable& other) { return value_ < other.value_; } 
    void setValue(int value) { value_ = value; } 
    std::ostream& print(std::ostream& os) const { return os << value_; } 
private: 
    NoCopyable& operator=(const NoCopyable& other); 
    int value_; 
}; 

std::ostream& operator<<(std::ostream& os, const NoCopyable& obj) 
{ 
    return obj.print(os); 
} 

struct PrintNoCopyable 
{ 
    void operator()(const NoCopyable& noCopyable) { std::cout << noCopyable << '\n'; } 
}; 

el compilador plantea este error error 1 error C2248: 'NoCopyable operador :: =': no ​​se puede miembro privado de acceso declarado en la clase 'NoCopyable'

lo tanto, he modificar ligeramente el código utilizando en lugar del std :: swap de funcionar mi versión de la función de intercambio, aquí está el código:

template<typename T1, 
     typename T2> 
void noAssignmentSwap(T1& t1,T2& t2) 
{ 
    T1 temp(t1); 
    t1.~T1(); 
    new (&t1) T1(t2); 
    t2.~T2(); 
    new (&t2) T2(temp); 
} 

El código se compila y da el resultado correcto. Sin embargo, no estoy del todo seguro, recuerdo un artículo de Sutter que sugiere que evites jugar con los objetos de por vida. El artículo te advierte jugando con fuego sin darte ninguna razón real. Puedo ver un problema en la seguridad de excepciones si el constructor de copias de T1 o T2 puede lanzar. Sin embargo, existe el mismo problema en la versión estándar si el operador de asignación puede lanzar.

Aquí la pregunta, ¿puedes ver los posibles inconvenientes en esta versión de intercambio?

Saludos

+0

llamadas de destructor explícito son raramente necesarias ... se ve iffy imho –

+1

¿Por qué utiliza dos tipos diferentes en el intercambio? si son diferentes usando el constructor de colocación para un objeto con la dirección del otro va a ser muy malo ... – 6502

+0

@ punto bueno, debería ser solo un parámetro de plantilla –

Respuesta

6

La diferencia es que cuando el operador de asignación falla, usted todavía tiene el mismo número de objetos.

Si destruye un objeto y no puede crear uno nuevo, ¡se pierde un objeto! Si era parte de un contenedor, el estado del contenedor probablemente tampoco sea válido.

3

Podría ser confuso para un futuro mantenedor del código.

8

Aparte de todo lo demás, si una clase no tiene un operador de asignación, es probable que su diseñador no tenga la intención de que se canjee. Si lo hicieron, probablemente también deshabilitaron la construcción de copias, por lo que su nueva función de intercambio aún no funcionará.

En cuanto a su afirmación de que los contenedores de la Biblioteca estándar no necesitan asignación, eso es cierto siempre que no desee realmente hacer algo útil con ellos. ¿Compila este código para usted?

#include <vector> 
using namespace std; 

struct A { 
    private: 
     void operator=(const A &); 
}; 

int main() { 
    vector <A> v; 
    v.push_back(A()); 
    v[0] = A();  // assignment needed here 
} 

Creo que no lo hará.

+0

+1. Buena respuesta. ¡Muy precisado! – Nawaz

+0

@Neil Butterworth si el constructor de copia del objeto está desactivado, el objeto no se puede usar con el contenedor stl, por lo que no hay mucho que ordenar. –

+0

@Alessandro ¿Está tratando con objetos que no se pueden asignar pero que se pueden copiar? Tales son bastante raros, en mi experiencia. Y su pregunta es explícitamente sobre swap(). –

4

Necesita un copiador en lugar de un operador de asignación, pero los dos son lo suficientemente similares que, al menos en un caso típico, tendrá ambos o no tendrá ninguno. IOW, no creo que esto generalmente logre mucho.

Lo clasificaría junto con el truco xor-swap: interesante, pero en general inútil.

Cuestiones relacionadas