c++ - definicion - Inicializando una unión con un constructor no trivial
constructor c++ definicion (6)
Tengo una estructura que creo un constructor personalizado para inicializar los miembros a los 0. He visto en compiladores más antiguos que cuando están en modo de lanzamiento, sin hacer un memset a 0, los valores no se inicializan.
Ahora quiero usar esta estructura en una unión, pero obtengo errores porque tiene un constructor no trivial.
Entonces, pregunta 1. ¿El constructor implementado por defecto del compilador garantiza que todos los miembros de una estructura serán inicializados nulos? El constructor no trivial solo hace un memset de todos los miembros a ''0'' para asegurar una estructura limpia.
Pregunta 2: Si se debe especificar un constructor en la estructura base, ¿cómo se puede implementar una unión para contener ese elemento y garantizar un elemento base inicializado 0?
Los miembros de la unión AFAIK pueden no tener constructores o destructores.
Pregunta 1: no, no hay tal garantía. Cualquier miembro de POD que no esté en la lista de inicialización del constructor se inicializa por defecto, pero eso es con un constructor que usted define y tiene una lista de inicializadores. Si no define un constructor, o si define un constructor sin una lista de inicializadores y un cuerpo vacío, los miembros POD no se inicializarán.
Los miembros que no son POD siempre se construirán a través de su constructor predeterminado, que si se sintetiza, nuevamente no inicializaría los miembros de POD. Dado que los miembros del sindicato pueden no tener constructores, se podría garantizar que los miembros de POD de las estructuras de una unión no se inicializarán.
Pregunta 2: siempre puede inicializar estructuras / uniones de la siguiente manera:
struct foo
{
int a;
int b;
};
union bar
{
int a;
foo f;
};
bar b = { 0 };
Pregunta 1: los constructores por defecto inicializan los miembros POD a 0 según el estándar C ++. Ver el texto citado a continuación.
Pregunta 2: Si se debe especificar un constructor en una clase base, esa clase no puede ser parte de una unión.
Finalmente, puede proporcionar un constructor para su sindicato:
union U
{
A a;
B b;
U() { memset( this, 0, sizeof( U ) ); }
};
Para Q1:
De C ++ 03, 12.1 Constructores, pg 190
El constructor predeterminado implícitamente definido realiza el conjunto de inicializaciones de la clase que realizaría un constructor predeterminado escrito por el usuario para esa clase con una lista-inicializador-memoria vacía (12.6.2) y un cuerpo de función vacío.
Desde C ++ 03, 8.5 Inicializadores, pg 145
Para inicializar por defecto un objeto de tipo T significa:
- si T es un tipo de clase no POD (cláusula 9), se llama al constructor predeterminado para T (y la inicialización está mal formada si T no tiene un constructor por defecto accesible);
- si T es un tipo de matriz, cada elemento se inicializa por defecto;
- de lo contrario, el objeto tiene cero inicialización .
Inicializar a cero un objeto de tipo T significa:
- si T es un tipo escalar (3.9), el objeto se establece en el valor de 0 (cero) convertido a T;
- si T es un tipo de clase no-unión, cada miembro de datos no estático y cada subobjeto de clase base tiene cero inicialización ;
- si T es un tipo de unión, el primer miembro de datos con nombre del objeto se inicializa en cero;
- si T es un tipo de matriz, cada elemento tiene cero inicialización;
- si T es un tipo de referencia, no se realiza ninguna inicialización.
Para Q2:
De C ++ 03, 12.1 Constructores, pg 190
Un constructor es trivial si es un constructor predeterminado implícitamente declarado y si:
- su clase no tiene funciones virtuales (10.3) ni clases base virtuales (10.1), y
- todas las clases base directas de su clase tienen constructores triviales, y
- para todos los miembros de datos no estáticos de su clase que son del tipo de clase (o conjunto de ellos), cada clase tiene un constructor trivial
De C ++ 03, 9.5 Uniones, pg 162
Una unión puede tener funciones miembro (incluidos constructores y destructores), pero no funciones virtuales (10.3). Una unión no debe tener clases base. Una unión no se utilizará como una clase base. Un objeto de una clase con un constructor no trivial (12.1), un constructor de copia no trivial (12.8), un destructor no trivial (12.4) o un no trivial el operador de asignación de copia (13.5.3, 12.8) no puede ser miembro de una unión, ni puede una matriz de tales objetos
Tendrá que esperar que C ++ 0x sea compatible con los compiladores para obtener esto. Hasta entonces, lo siento.
Las cosas cambiaron para mejor en C ++ 11.
Ahora puede hacer esto legalmente, como lo describe el mismo Stroustrup (llegué a ese enlace del artículo de Wikipedia sobre C ++ 11 ).
El ejemplo en Wikipedia es el siguiente:
#include <new> // Required for placement ''new''.
struct Point {
Point() {}
Point(int x, int y): x_(x), y_(y) {}
int x_, y_;
};
union U {
int z;
double w;
Point p; // Illegal in C++03; legal in C++11.
U() {new(&p) Point();} // Due to the Point member, a constructor
// definition is now *required*.
};
Stroustrup entra un poco más de detalle.
Como se menciona en el comentario de Greg Rogers a la publicación de unwesen , puede darle a su sindicato un constructor (y destructor si lo desea):
struct foo
{
int a;
int b;
};
union bar
{
bar() { memset(this, 0, sizeof(*this)); }
int a;
foo f;
};
¿Puedes hacer algo como esto?
class Outer
{
public:
Outer()
{
memset(&inner_, 0, sizeof(inner_));
}
private:
union Inner
{
int qty_;
double price_;
} inner_;
};
... o tal vez algo como esto?
union MyUnion
{
int qty_;
double price_;
};
void someFunction()
{
MyUnion u = {0};
}