2011-08-24 8 views
6

Antecedentes: Tengo una clase complicada con muchas variables. Tengo un sonido y probado constructor de copia:¿Puedo usar la ubicación nueva (this) en operator =?

Applepie::Applepie(const Applepie &copy) : 
m_crust(copy.m_crust), 
m_filling(copy.m_filling) 
{ 
} 

Algunos de los constructores de copia variable miembro llamada en la lista intializer realizar la asignación.

Pregunta: Necesito crear operator=. En lugar de duplicar la Constuctor existente con la asignación en lugar de lista de inicialización, y la memoria de la liberación que está siendo reemplazado, y etc, etc, etc, puedo simplemente hacer lo siguiente:

Applepie& Applepie::operator=(const Applepie &copy) 
{ 
    if(this != &copy) 
    { 
     this->~Applepie(); // release own object 
     new(this) Applepie(copy); // placement new copy constructor 
    } 
    return *this; 
} 

En otras palabras, es destruir el auto seguido de una colocación nuevo constructor de copia semánticamente idéntico a operator =?

Esto parece tener el potencial de reducir drásticamente la repetición de código y confirmar que cada variable se inicializa correctamente, a costa de una ligera pérdida potencial de eficiencia durante la asignación. ¿Me estoy perdiendo algo más oscuro?

Justificación: Mi clase real tiene aproximadamente 30 varaibles. Me preocupa el hecho de que tanto mi constructor de copia como mi operador de asignación tengan que copiar los treinta, y que el código pueda divergir, haciendo que las dos operaciones hagan las cosas de manera diferente.

+4

Si el controlador de copia tira, ha roto el objeto, por lo que no está dando garantías de seguridad. –

+1

@R Martinho - Me parece que cualquier situación en la que el controlador de copia arrojaría también causaría que mi operador = arrojara si estuviera asignando manualmente cada variable ... Entonces ... ¿eso todavía parece equivalente? – jcwenger

+3

el problema no es 'operator =' throwing, es 'operator =' dejando el objeto en un estado inválido! Ha sido destruido. –

Respuesta

6

Como Herb Sutter en los estados "Excepcional C++", no es una excepción segura. Eso significa que, si algo va mal durante new o la construcción del nuevo objeto, el operando de la mano izquierda de la asignación está en estado incorrecto (indefinido), lo que genera más problemas. Recomiendo usar el copy & swap idiom.

Applepie& Applepie::operator=(Applepie copy) 
{ 
    swap(m_crust, copy.m_crust); 
    swap(m_filling, copy.m_filling); 
    return *this; 
} 

Cuando su objeto utiliza el lenguaje Pimpl (puntero a la implementación) También, el canje se hace cambiando sólo dos punteros.

+1

+1 'swap' es un maravilloso infravalorado función ... Ventaja adicional: el compilador puede realizar elisión de copia si el argumento es un valor r. –

+0

Entonces ... Mi problema con esto es que mi clase real tiene alrededor de 30 variables. Mi constructor de copia tiene todas las 30 variables en la lista de inicializadores. copiar y cambiar aún requerirá que tenga 30 llamadas swap() - mi objetivo es reducir la probabilidad de que Applepie pie (original); y manzana Applepie; apple = original; producir diferentes resultados – jcwenger

+0

@jcwenger: Sí, eso es un llamado a problemas. Por lo tanto, podría ser un candidato para el modismo * Pimpl *, pero antes de cambiar a eso, considere que tiene un costo: cada acceso de miembro pasa por un puntero en ese momento. Otra idea sería dividir tu clase 'Applepie' en pedazos más pequeños. Si tiene 30 miembros de datos en una clase, algo podría estar mal con el diseño ... –

0

Además de la respuesta de Rene, también está el problema de qué pasaría si ApplePie fuera una clase base del objeto real: ApplePie reemplazaría el objeto con un objeto del tipo incorrecto.

+1

El operador = haría * rebanar objetos * de todos modos, si el objeto no está implementado en un idioma Handle-Worker. –

Cuestiones relacionadas