c++ assignment-operator

c++ - ¿Hay situaciones en las que la autoasignación es útil?



assignment-operator (3)

Es comúnmente conocido que cuando se implementa un operador de asignación se debe proteger contra la autoasignación, al menos cuando la clase no tiene miembros POD. Normalmente es (o es equivalente a):

Foo& operator=(const Foo& other) { if (&other == this) return *this; ... // Do copy }

¿Cuáles fueron las razones para no insertar la protección de autoasignación automáticamente? ¿Hay casos de uso cuando la autoasignación hace algo no trivial y útil en la práctica?

Foo& operator=(const Foo& other) { if (&other == this) { // Do something non-trivial } else { // Do copy } return *this; }

Para resumir las respuestas y la discusión a estas alturas.

Parece que la autoasignación no trivial nunca puede ser realmente útil. La única opción propuesta fue poner una assert allí para detectar algunos errores lógicos. Pero hay casos de a = std::min(a, b) bastante legítimos como a = std::min(a, b) , por lo que incluso esta opción es muy dudosa.

Pero hay dos posibles implementaciones de una autoasignación trivial:

  1. No hacer nada si &other == this . Siempre funciona, aunque puede tener un impacto negativo en el rendimiento debido a una ramificación adicional. Pero en un operador de asignación definido por el usuario, la prueba debe realizarse casi siempre explícitamente.
  2. Copia cada miembro a si mismo. Esto es lo que se hace por defecto. Si los miembros también usan operadores de asignación predeterminados, puede ser más rápido, porque no requiere una ramificación adicional.

Todavía no veo por qué el estándar de C ++ no puede garantizar que en un operador de asignación definido por el usuario &other != this . Si no desea bifurcar, use el operador predeterminado. Si está redefiniendo el operador, se necesita alguna prueba de todos modos ...


Debo admitir que nunca he oído hablar del conocimiento común como este. Para los objetos que no son POD, un enfoque más estricto es prohibir la copia con el constructor de copia inhabilitado y el operador de asignación. Para que no tengas el problema en absoluto.

Si aún necesita copiar la clase, pero hay algunos datos que no es seguro copiarse a sí mismo, solo podría anular la asignación de esos datos, y cuando se usa como un campo, sería utilizado por una implementación de asignación automática de la clase de nivel superior.

En cuanto a su pregunta, si solo necesita omitir hacer algo, la "protección de autoasignación" automática ya está ahí, de alguna manera. Si no define explícitamente la operación de asignación y deja que el compilador use la automática, después de que la autoasignación en línea se convierta en no operativa.

Por ejemplo, el siguiente código:

class A { int a; double b; }; A& foo(A& input) { return (input = input); }

se compila a (gcc 4.9, -O2):

_Z3fooR1A: .cfi_startproc movq %rdi, %rax ret .cfi_endproc

Que no copia nada.


Hay algoritmos donde puede suceder.

  1. Sabes que lhs y rhs podrían ser iguales, pero es más simple hacer la tarea que verificar. Por ejemplo, considere a = std::min(a,b); - más simple y quizás más fácil de entender que if (a > b) a = b; - Consideremos ahora ejemplos más complicados de cosas similares.

  2. No sabes si lhs y rhs podrían ser iguales, porque pueden haber sido transmitidos desde otro lugar.

Estos algoritmos donde puede ocurrir no son infrecuentes.


La protección de autoasignación solo es necesaria para los tipos en los que el código que se omite es peligroso cuando se aplica a sí mismo. Considere el caso en el que tiene un operador de asignación proporcionado por el usuario porque cada objeto individual tiene algún tipo de identificador, que no desea copiar. Bueno, puede "copiar" los otros valores bien en casos de autoasignación. Por lo tanto, insertar una prueba de autoasignación invisible es simplemente agregar una rama condicional sin sentido y potencialmente costosa.

Así que no se trata de que la autoasignación sea útil; Se trata de la autoasignación que no siempre necesita protección.

Además, a C ++ generalmente no le gusta agregar código como ese a tu código sin que lo solicites explícitamente. Normalmente se hace en términos de funciones completas, no parte de funciones. Incluso las llamadas al destructor al final de los bloques son algo que pidió cuando puso el objeto a destruir en la pila.