c++ language-lawyer

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 .