versiones existentes dev compiler c++ c++11

existentes - Garantía y nombre de C++ para datos similares a POD, con capacidad memcpy



dev c++ (4)

En C ++ 0x, el concepto de PODness se divide en varias categorías individualmente útiles:

Una clase trivialmente copiable es una clase que (borrador 3242, sección [class] ):

  • 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).

Una clase trivial es una clase que tiene un constructor predeterminado trivial (12.1) y se puede copiar de forma trivial.

[ Nota: en particular, una clase trivialmente copiable o trivial no tiene funciones virtuales o clases base virtuales. - nota final ]

Una clase de diseño estándar es una clase que:

  • no tiene miembros de datos no estáticos de tipo clase de diseño no estándar (o matriz de tales tipos) o referencia,
  • no tiene funciones virtuales (10.3) ni clases de base virtual (10.1),
  • tiene el mismo control de acceso (Cláusula 11) para todos los miembros de datos no estáticos,
  • no tiene clases de base de diseño no estándar,
  • o no tiene miembros de datos no estáticos en la clase más derivada y, como máximo, una clase base con miembros de datos no estáticos, o no tiene clases base con miembros de datos no estáticos, y
  • no tiene clases base del mismo tipo que el primer miembro de datos no estáticos.

Los requisitos para los constructores triviales, operadores de asignación y destructor se encuentran dispersos en la sección 12 "Funciones especiales para miembros" [special] .

En otra question , utilicé incorrectamente el término POD para referirme a los tipos de datos que en realidad no son tipos de POD (por tener un constructor). Ahora, he revisado el estándar y no pude encontrar un nombre adecuado para lo que quiero. Tampoco puedo encontrar una garantía de que la copia esté realmente permitida.

El tipo de datos al que me refiero es un POD, pero puede contener funciones, incluidos los constructores, pero nada que deba alterar su alineación o sus características de tamaño cuando se compara con un tipo de POD equivalente.

En la sección 3.9 del estándar, se establece que los datos POD se pueden copiar con memcpy, ya sea en otro objeto, o en datos de caracteres y viceversa. Nunca se hace tal garantía de datos no POD.

Sin embargo, la representación del objeto de un objeto se define en la misma sección. Se define de tal manera que uno podría creer que dos objetos del mismo tipo podrían copiarse de forma segura a través de memcpy.

Así que mis preguntas son:

  1. ¿Se garantiza que la copia con memcpy sea segura para tales objetos?
  2. Si es así, ¿por qué hay una nota especial sobre memcpy y POD?
  3. ¿Hay un nombre para este tipo de datos que sea seguro para memcpy?

Un ejemplo simple del tipo de objeto que quiero decir:

struct ex_struct { int a,b,c,d; ex_struct() : a(123) { } }

Al leer el borrador de C ++ 0x, mi estructura parece ser una clase que se puede copiar de forma trivial (9.1). Creo que eso implica que memcpy estaría a salvo.


La noción de POD en C ++ 03 es ciertamente muy estricta. En C ++ 0x, el POD se generaliza para incluir los objetos que describió también. Así que no te preocupes, puedes llamarlo POD. Ver un buen verano en Wikipedia .


Sí, es seguro copiar con memcpy porque el constructor solo inicializa los valores.


Un problema con su ejemplo es que tiene un destructor trivial declarado implícitamente. A pesar del nombre, la implementación no está prohibida por AFAIK de hacer algo en un destructor trivial de una clase no POD.

Así que legalmente en alguna implementación extraña, su clase ex_struct podría exhibir un comportamiento de tiempo de ejecución equivalente al siguiente:

struct weird_ex_struct { int a,b,c,d; weird_ex_struct() : a(123), aptr(&a) { } weird_ex_struct(const weird_ex_struct &o) : a(o.a), b(o.b), c(o.c), d(o.d), aptr(&a) {} weird_ex_struct &operator=(const weird_ex_struct &o) { a = o.a; //etc aptr = &a; return *this; } ~weird_ex_struct() { if (aptr != &a) std::terminate(); } private: int *aptr; }

Digo comportamiento de tiempo de ejecución, porque weird_ex_struct tiene un destructor no trivial, y eso afecta la forma en que se puede usar legalmente (no en uniones, por ejemplo). También creo que hay formas estándar de detectar la existencia de miembros de datos privados en tiempo de compilación. Pero mientras la implementación pueda mantener estas cosas en secreto a menos que hagas algo indefinido ( memcpy un objeto que no sea POD), entonces se te permite memcpy la sorpresa más tarde.

Claramente, si weird_ex_struct se copia con memcpy , entonces algo extraño sucederá cuando se destruya.

No hay una razón obvia para que una implementación haga esto, pero el estándar dejó las clases no POD abiertas para que las implementaciones puedan hacer cosas extrañas. No estoy seguro de si esto se debe a que pensaron que alguien pensaría en alguna rareza útil, o simplemente porque no lograron definir el diseño estándar como lo hace C ++ 0x.

[Editar: Johannes ha señalado que estoy equivocado acerca de los destructores triviales, por razones expuestas en la parte del estándar que trata sobre la vida útil de los objetos, una implementación no puede hacer cosas en los destructores triviales que dependen del contenido de la memoria del objeto. Posiblemente puedan hacerlo si el destructor se llama explícitamente, no estoy seguro.

Sin embargo, el hecho es que el estándar permite que las implementaciones realicen bastantes locuras con objetos que no son POD, y en cuanto escribes un constructor, abres esa puerta.]