J'ai une structure que je crée un constructeur personnalisé pour initialiser les membres à 0. J'ai vu dans des compilateurs plus anciens qu'en mode release, sans faire un memset à 0, les valeurs ne sont pas initialisées.
Je veux maintenant utiliser cette structure dans une union, mais j'obtiens des erreurs car elle a un constructeur non trivial.
Donc, question 1. Le constructeur implémenté par le compilateur par défaut garantit-il que tous les membres d'une structure seront initialisés à zéro? Le constructeur non trivial fait juste un memset de tous les membres à '0' pour assurer une structure propre.
Question 2: Si un constructeur doit être spécifié sur la structure de base, comment une union peut-elle être implémentée pour contenir cet élément et garantir un élément de base initialisé à 0?
Question 1: les constructeurs par défaut initialisent les membres POD à 0 selon la norme C++. Voir le texte cité ci-dessous.
Question 2: Si un constructeur doit être spécifié dans une classe de base, alors cette classe ne peut pas faire partie d'une union.
Enfin, vous pouvez fournir un constructeur pour votre syndicat:
union U
{
A a;
B b;
U() { memset( this, 0, sizeof( U ) ); }
};
Pour Q1:
À partir de C++ 03, 12.1 Constructors, pg 190
Le constructeur par défaut défini implicitement effectue l'ensemble des initialisations de la classe qui seraient effectuées par un constructeur par défaut écrit par l'utilisateur pour cette classe avec une liste d'initialiseurs mem vide (12.6.2) et un corps de fonction vide.
De C++ 03, 8.5 Initialiseurs, p. 145
Initialiser par défaut un objet de type T signifie:
Initialiser à zéro un objet de type T signifie:
Pour le T2:
À partir de C++ 03, 12.1 Constructors, pg 190
Un constructeur est trivial s'il s'agit d'un constructeur par défaut déclaré implicitement et si:
À partir de C++ 03, 9.5 Unions, p. 162
Une union peut avoir des fonctions membres (y compris des constructeurs et des destructeurs), mais pas de fonctions virtuelles (10.3). Un syndicat ne doit pas avoir de classes de base. Une union ne doit pas être utilisée comme classe de base.Un objet d'une classe avec un constructeur non trivial (12.1), un constructeur de copie non trivial (12.8), un destructeur non trivial (12.4) ou un non trivial L'opérateur d'affectation de copie (13.5.3, 12.8) ne peut pas être membre d'une union, pas plus qu'un tableau de ces objets
Les choses ont changé pour le mieux en C++ 11.
Vous pouvez maintenant le faire légalement, comme décrit par Stroustrup lui-même (j'ai atteint ce lien depuis le article Wikipedia sur C++ 11 ).
L'exemple sur Wikipédia est le suivant:
#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 va dans un peu plus de détails.
Les membres du syndicat AFAIK ne peuvent pas avoir de constructeurs ou de destructeurs.
Question 1: non, il n'y a pas de telle garantie. Tout membre POD ne figurant pas dans la liste d'initialisation du constructeur est initialisé par défaut, mais c'est avec un constructeur que vous définissez et possède une liste d'initialisation. Si vous ne définissez pas de constructeur, ou si vous définissez un constructeur sans liste d'initialisation et corps vide, les membres POD ne seront pas initialisés.
Les membres non POD seront toujours construits via leur constructeur par défaut qui, s'il était synthétisé, n'initialiserait pas non plus les membres POD. Étant donné que les membres d'union peuvent ne pas avoir de constructeurs, vous seriez à peu près assuré que les membres POD des structures dans une union ne seront pas initialisés.
Question 2: vous pouvez toujours initialiser des structures/unions comme ceci:
struct foo
{
int a;
int b;
};
union bar
{
int a;
foo f;
};
bar b = { 0 };
Comme mentionné dans le commentaire de Greg Rogers à nwesen , vous pouvez donner à votre syndicat un constructeur (et un destructeur si vous le souhaitez):
struct foo
{
int a;
int b;
};
union bar
{
bar() { memset(this, 0, sizeof(*this)); }
int a;
foo f;
};
Pouvez-vous faire quelque chose comme ça?
class Outer
{
public:
Outer()
{
memset(&inner_, 0, sizeof(inner_));
}
private:
union Inner
{
int qty_;
double price_;
} inner_;
};
... ou peut-être quelque chose comme ça?
union MyUnion
{
int qty_;
double price_;
};
void someFunction()
{
MyUnion u = {0};
}