2011-10-26 12 views
25

¿Es esta una manera válida de crear un operador de asignación con miembros que son referencias?Operador de asignación con miembros de referencia

#include <new> 

struct A 
{ 
    int &ref; 
    A(int &Ref) : ref(Ref) { } 
    A(const A &second) : ref(second.ref) { } 
    A &operator =(const A &second) 
    { 
     if(this == &second) 
      return *this; 
     this->~A(); 
     new(this) A(second); 
     return *this; 
    } 
} 

Parece compilar y ejecutar bien, pero con C++ superficie de tendencia a un comportamiento indefinido cuando menos se espera, y todas las personas que dicen que es imposible, me parece que una de gotcha echaba de menos. ¿Yo me perdí algo?

+0

Por cierto, los argumentos a 'operador =' y el constructor de copia deben ser referencias const. –

+1

La corrección puede estar limitada a los tipos de diseño estándar, ya que con los virtuales 'este' no necesita ser un puntero al comienzo del bloque de memoria. –

+6

Si necesita hacer esto, le sugiero que reconsidere el uso de referencias. – bames53

Respuesta

31

Es sintácticamente correcto. Sin embargo, si la colocación nueva arroja, usted termina con un objeto que no puede destruir. Sin mencionar el desastre si alguien proviene de su clase. Simplemente no lo hagas.

La solución es simple: si la clase necesita compatibilidad con la asignación, no use ningún miembro de referencia. Tengo muchas clases que toman los argumentos de referencia , pero los almacena como punteros, solo para que la clase pueda admitir la asignación . Algo así como:

struct A 
{ 
    int* myRef; 
    A(int& ref) : myRef(&ref) {} 
    // ... 
}; 
+0

+1, eso es lo que hago. –

+0

Me gusta: ¡solución directa! – aardvarkk

3

Lo que hace es técnicamente correcto hasta donde yo sé, pero genera problemas. Por ejemplo, considere lo que sucede con una clase derivada de A, ya que su operador de asignación genera un nuevo objeto (slicing). ¿No puedes simplemente convertir la referencia en un puntero dentro de tu clase?

Además de eso, los constructores de copia y los operadores de asignación suelen tomar su argumento por const&.

+0

¿Cómo genera esto un problema? –

1

Lo que usted hace es correcto, pero no es una excepción la forma segura de escribir un operador de asignación de copias. Además, debe considerar usar un miembro de puntero en lugar de un miembro de referencia.

Debe implementarlo usando Copy and Swap Idiom. Tiene al menos 3 ventajas sobre su implementación.

+0

Pero, ¿cómo cambiar las referencias? –

+0

@ChristianRau: de todos modos estarías implementando tu propia función 'swap'. –

+0

Sí, y esto probablemente necesite cambiar las referencias. –

2

Otra solución es utilizar la clase reference_wrapper (en la cabecera funcional):

struct A 
{ 
    A(int& a) : a_(a) {} 
    A(const A& a) : a_(a.a_) {} 

    A& operator=(const A& a) 
    { 
     a_ = a.a_; 
     return *this; 
    } 

    void inc() const 
    { 
     ++a_; 
    } 

    std::reference_wrapper<int>a_; 

}; 
Cuestiones relacionadas