¿Condiciones para la generación automática de un operador de asignación predeterminado / copiar / mover y copiar / mover asignación?
127
Quiero actualizar mi memoria en las condiciones en que un compilador generalmente genera automáticamente un constructor predeterminado, un constructor de copia y un operador de asignación.
Recuerdo que había algunas reglas, pero no recuerdo, y tampoco puedo encontrar un recurso confiable en línea. ¿Alguien puede ayudar?
A continuación, "autogenerado" significa "declarado implícitamente como predeterminado, pero no definido como eliminado". Hay situaciones en las que se declaran las funciones miembro especiales, pero se definen como eliminadas.
El constructor predeterminado se genera automáticamente si no hay un constructor declarado por el usuario (§12.1 / 5).
El constructor de copia se genera automáticamente si no hay un constructor de movimiento u operador de asignación de movimiento declarado por el usuario (porque no hay constructores de movimiento u operadores de asignación de movimiento en C ++ 03, esto se simplifica a "siempre" en C ++ 03) ( §12.8 / 8).
El operador de asignación de copia se genera automáticamente si no hay un constructor de movimiento u operador de asignación de movimiento declarado por el usuario (§12.8 / 19).
El destructor se genera automáticamente si no hay un destructor declarado por el usuario (§12.4 / 4).
C ++ 11 y posterior solamente:
El constructor de movimiento se genera automáticamente si no hay un constructor de copia, un operador de asignación de copia o un destructor declarado por el usuario, y si el constructor de movimiento generado es válido (§12.8 / 10).
El operador de asignación de movimiento se genera automáticamente si no hay un constructor de copia, un operador de asignación de copia o destructor declarado por el usuario, y si el operador de asignación de movimiento generado es válido (por ejemplo, si no fuera necesario asignar miembros constantes) (§12.8 / 21)
¿Cuenta un destructor heredado? Quiero decir, digamos que tengo una clase base con un destructor virtual vacío. ¿Impide la creación de constructores de movimiento en subclases? Si la respuesta es sí, ¿será útil si defino un constructor de movimiento en la clase base?
kamilk
10
Creo que se debe mencionar que tal vez tener constmiembros en la clase evitará que el constructor de ser auto-generado ...
nonsensickle
"Hay situaciones en las que se declaran las funciones especiales del miembro, pero se definen como eliminadas" ¿Se refiere a dónde, por ejemplo, tiene miembros constantes o de referencia donde el movimiento será imposible? No, eso no puede ser, porque allí se aplicará una copia.
Towi
Sé que está restringido enviar hipervínculos en este foro. Pero también es un buen artículo - cplusplus.com/articles/y8hv0pDG
bruziuz
Tenga en cuenta que, a partir del estándar, un constructor de copia predeterminado implícitamente " queda en desuso si la clase tiene un operador de asignación de copia declarado por el usuario o un destructor declarado por el usuario " ( 12.8 Copiando y moviendo objetos de clase [class.copy] ).
Hermoso. ¿A qué se refiere "independiente"? ¿Independiente de qué?
Towi
8
La copia / asignación es 'independiente' entre sí. Si escribe solo uno, el compilador proporcionará el otro. Por el contrario, si proporciona un controlador de movimiento o una asignación de movimiento, el compilador no proporcionará el otro.
Marco M.
Me pregunto cuál es la razón de que las operaciones de copia sean independientes. Razones históricas pueden ser? ¿O el hecho de que la copia no modificará su objetivo, pero el movimiento sí?
RaGa__M
@Explorer_N Sí, compatibilidad con versiones anteriores, por razones históricas. Fue una mala elección de diseño hace mucho tiempo, por lo que ahora hay una necesidad de buenas prácticas como la "regla de tres" (definir los 3 o ninguno: constructor de copia, operador de asignación de copia y, a menudo, destructor) para evitar errores difíciles de encontrar.
atablash
@MarcoM., Por lo que he entendido, la condición "Si escribe ..." incluye los dos casos de establecer la función de miembro especial en = delete(obvio) o = default(menos obvio para mí). Estoy en lo cierto?
Enrico Maria De Angelis
2
C ++ 17 N4659 borrador estándar
Para una referencia estándar cruzada rápida, eche un vistazo a las secciones "Declaradas implícitamente" de las siguientes entradas de cppreference:
15.8.1 "Copiar / mover constructores" dice para el constructor de copias:
6 Si la definición de clase no declara explícitamente un constructor de copia, una no explícita se declara implícitamente. Si la definición de clase declara un constructor de movimiento o un operador de asignación de movimiento, el constructor de copia declarado implícitamente se define como eliminado; de lo contrario, se define como predeterminado (11.4). El último caso está en desuso si la clase tiene un operador de asignación de copia declarado por el usuario o un destructor declarado por el usuario.
y para mover constructor:
8 Si la definición de una clase X no declara explícitamente un constructor de movimiento, uno no explícito se declarará implícitamente como predeterminado si y solo si
(8.1) - X no tiene un constructor de copia declarado por el usuario,
(8.2) - X no tiene un operador de asignación de copia declarado por el usuario,
(8.3) - X no tiene un operador de asignación de movimiento declarado por el usuario, y
(8.4) - X no tiene un destructor declarado por el usuario.
15.8.2 "Operador de asignación de copiar / mover" dice para la asignación de copia:
2 Si la definición de clase no declara explícitamente un operador de asignación de copia, uno se declara implícitamente. Si la definición de clase declara un constructor de movimiento o un operador de asignación de movimiento, el operador de asignación de copia declarado implícitamente se define como eliminado; de lo contrario, se define como predeterminado (11.4). El último caso está en desuso si la clase tiene un constructor de copia declarado por el usuario o un destructor declarado por el usuario.
y para la asignación de movimiento:
4 Si la definición de una clase X no declara explícitamente un operador de asignación de movimiento, uno se declarará implícitamente como predeterminado si y solo si
(4.1) - X no tiene un constructor de copia declarado por el usuario,
(4.2) - X no tiene un constructor de movimiento declarado por el usuario,
(4.3) - X no tiene un operador de asignación de copia declarado por el usuario, y
(4.4) - X no tiene un destructor declarado por el usuario.
15.4 "Destructores" lo dice para destructores:
4 Si una clase no tiene un destructor declarado por el usuario, un destructor se declara implícitamente como predeterminado (11.4). Un destructor declarado implícitamente es un miembro público en línea de su clase.
const
miembros en la clase evitará que el constructor de ser auto-generado ...El siguiente diagrama me ha parecido muy útil.
de Sticky Bits: convertirse en un héroe de la regla de cero
fuente
= delete
(obvio) o= default
(menos obvio para mí). Estoy en lo cierto?C ++ 17 N4659 borrador estándar
Para una referencia estándar cruzada rápida, eche un vistazo a las secciones "Declaradas implícitamente" de las siguientes entradas de cppreference:
La misma información, por supuesto, se puede obtener de la norma. Por ejemplo, en C ++ 17 N4659 borrador estándar :
15.8.1 "Copiar / mover constructores" dice para el constructor de copias:
y para mover constructor:
15.8.2 "Operador de asignación de copiar / mover" dice para la asignación de copia:
y para la asignación de movimiento:
15.4 "Destructores" lo dice para destructores:
fuente