c++ - ¿Es una clase con copia-constructor borrado trivialmente copiable?
language-lawyer (1)
Es esta clase
class A {
public:
A() = default;
A(const A&) = delete;
};
¿Trivialmente copiable? (Al menos, clang parece pensar así).
En particular, lo haría
A a,b;
std::memcpy(&a, &b, sizeof(A));
invocar un comportamiento indefinido?
Contexto: Esta respuesta [se eliminó porque se demostró que está equivocada] más su árbol de comentarios.
Actualización : La resolución propuesta de CWG 1734 , actualmente en estado "listo", modificaría [clase] / p6 para que lea:
Una clase trivialmente copiable es una clase:
- donde cada constructor de copia, constructor de movimiento, operador de asignación de copia y operador de asignación de movimiento (12.8 [class.copy], 13.5.3 [over.ass]) se elimina o es trivial,
- que tenga al menos un constructor de copia no eliminado, constructor de movimiento, operador de asignación de copia u operador de asignación de movimiento, y
- que tiene un destructor trivial, no eliminado (12.4 [class.dtor]).
Esto hace que clases como
struct B {
B() = default;
B(const B&) = delete;
B& operator=(const B&) = delete;
};
Ya no se puede copiar trivialmente. (Las clases de este tipo incluyen primitivas de sincronización como std::atomic<T>
y std::mutex
).
Sin embargo, la A
en el OP tiene un operador de asignación de copia no eliminado, declarado implícitamente, que es trivial, por lo que permanece trivialmente copiable.
La respuesta original para la situación anterior a CWG1734 se conserva a continuación como referencia.
Sí, algo contraintuitivo, es trivialmente copiable. [clase] / p6:
Una clase trivialmente copiable es una clase que:
- no tiene constructores de copias no triviales (12.8),
- no tiene constructores de movimientos no triviales (12.8),
- no tiene operadores de asignación de copia no triviales (13.5.3, 12.8),
- no tiene operadores de asignación de movimientos no triviales (13.5.3, 12.8), y
- Tiene un destructor trivial (12.4).
[class.copy] / p12:
Un constructor de copiar / mover para la clase X es trivial si no es proporcionado por el usuario, su lista de tipos de parámetros es equivalente a la lista de tipos de parámetros de una declaración implícita, y si
- la clase X no tiene funciones virtuales (10.3) ni clases de base virtual (10.1), y
- la clase X no tiene miembros de datos no estáticos de tipo calificado volátil, y
- el constructor seleccionado para copiar / mover cada subobjeto de clase base directa es trivial, y
- para cada miembro de datos no estáticos de X que es de tipo de clase (o matriz de ellos), el constructor seleccionado para copiar / mover ese miembro es trivial;
Similarmente ([class.copy] / p25):
Un operador de asignación de copia / movimiento para la clase X es trivial si no es proporcionado por el usuario, su lista de tipos de parámetros es equivalente a la lista de tipos de parámetros de una declaración implícita, y si
- la clase X no tiene funciones virtuales (10.3) ni clases de base virtual (10.1), y
- la clase X no tiene miembros de datos no estáticos de tipo calificado volátil, y
- el operador de asignación seleccionado para copiar / mover cada subobjeto de clase base directa es trivial, y
- para cada miembro de datos no estáticos de X que es de tipo de clase (o conjunto de ellos), el operador de asignación seleccionado para copiar / mover ese miembro es trivial;
[class.dtor] / p5:
Un destructor es trivial si no es proporcionado por el usuario y si:
- el destructor no es
virtual
,- todas las clases base directas de su clase tienen destructores triviales, y
- para todos los miembros de datos no estáticos de su clase que son de tipo de clase (o conjunto de los mismos), cada clase tiene un destructor trivial.
[dcl.fct.def.default] / p5:
Una función es proporcionada por el usuario si es declarada por el usuario y no está predeterminada o eliminada de forma explícita en su primera declaración.
De hecho, esto ha sido una fuente de problemas para el propio comité , porque bajo la definición actual atomic<T>
(junto con las mutexes y las variables de condición) sería trivialmente copiable. (Y, obviamente, permitir que alguien memcpy
un atomic
o mutex
sin invocar a UB sería ... digamos, seriamente problemático). Consulte también N4460 .