Les membres d'une structure C ++ sont-ils initialisés à 0 par défaut?

201

J'ai ceci struct:

struct Snapshot
{
    double x; 
    int y;
};

Je veux xet yêtre 0. Seront-ils 0 par défaut ou dois-je faire:

Snapshot s = {0,0};

Quelles sont les autres façons de mettre à zéro la structure?

ks1322
la source
Utilisez un std :: map <> et retournez 0 lorsqu'une clé n'existe pas.
Jonny

Réponses:

264

Ils ne sont pas nuls si vous n'initialisez pas la structure.

Snapshot s; // receives no initialization
Snapshot s = {}; // value initializes all members

Le second mettra tous les membres à zéro, le premier les laisse à des valeurs non spécifiées. Notez qu'il est récursif:

struct Parent { Snapshot s; };
Parent p; // receives no initialization
Parent p = {}; // value initializes all members

Le second fera p.s.{x,y}zéro. Vous ne pouvez pas utiliser ces listes d'initialisation agrégées si vous avez des constructeurs dans votre structure. Si tel est le cas, vous devrez ajouter une bonne initialisation à ces constructeurs

struct Snapshot {
    int x;
    double y;
    Snapshot():x(0),y(0) { }
    // other ctors / functions...
};

Initialise à la fois x et y à 0. Notez que vous pouvez utiliser x(), y()pour les initialiser sans tenir compte de leur type: c'est alors l'initialisation de la valeur, et donne généralement une valeur initiale correcte (0 pour int, 0,0 pour double, appelant le constructeur par défaut pour défini par l'utilisateur types qui ont des constructeurs déclarés par l'utilisateur, ...). Ceci est important surtout si votre structure est un modèle.

Johannes Schaub - litb
la source
1
Cela produit de nombreux avertissements dans mon compilateur.
River-Claire Williamson
1
Roger: Essayez d'utiliser la structure nommée dans l'initialiseur, c'est ce que je fais et je ne reçois aucun avertissement dans VC 2012: Snapshot s = Snapshot ();
Kit10
@Johannes Schaub - litb Fonctionnera-t-il Snapshot s = {};pour les non-membres du POD (pour les mettre à zéro)?
ontherocks
2
C ++ 11 vous permet maintenant de les initialiser dans la définition de la structure ou de la classe, comme ceci: struct Snapshot {double x {0}; // avec accolades int y = 0; // ou juste du style old school 'par affectation' qui est aussi vraiment l'initialisation};
ikku100
1
Est-ce que "Snapshot s = {};" fait partie de la norme?
Stefan
41

Non, ils ne sont pas 0 par défaut. Le moyen le plus simple de s'assurer que toutes les valeurs ou par défaut à 0 est de définir un constructeur

Snapshot() : x(0), y(0) {
}

Cela garantit que toutes les utilisations de Snapshot auront des valeurs initialisées.

JaredPar
la source
24
L'inconvénient est que la structure n'est plus un type POD, car elle a un constructeur. Cela interrompra certaines opérations telles que l'écriture dans un fichier temporaire.
finnw
16
@finnw: C ++ 11 corrige cela, bien que la structure ne soit pas POD, c'est une "disposition standard".
Ben Voigt
20

En général, non. Cependant, une structure déclarée comme portée de fichier ou statique dans une fonction / sera / sera initialisée à 0 (comme toutes les autres variables de ces étendues):

int x; // 0
int y = 42; // 42
struct { int a, b; } foo; // 0, 0

void foo() {
  struct { int a, b; } bar; // undefined
  static struct { int c, d; } quux; // 0, 0
}
bdonlan
la source
1
Ce n'est vraiment pas une hypothèse sûre. vous ne devez pas vous fier à la valeur de tout ce que vous n'avez pas initialisé
Hasturkun
24
Les objets de durée de stockage statique sont toujours initialisés à zéro - voir stackoverflow.com/questions/60653/… pour une citation de la norme. Que ce soit du bon style est une autre affaire.
bdonlan
12

Avec POD, vous pouvez également écrire

Snapshot s = {};

Vous ne devez pas utiliser memset en C ++, memset a l'inconvénient que s'il y a un non-POD dans la structure, il le détruira.

ou comme ça:

struct init
{
  template <typename T>
  operator T * ()
  {
    return new T();
  }
};

Snapshot* s = init();
AndersK
la source
@LightnessRacesinOrbit oh wat?
Ben Sinclair
@Andy Most Vexing Parse transforme des choses qui ressemblent à des cteurs normaux - SomeType foo();c'est le cas typique, bien que cela puisse arriver avec d'autres - en définitions de fonctions (dans ce cas, une fonction fooqui revient SomeType). Désolé pour la nécro, mais si quelqu'un d'autre tombe dessus, j'ai pensé que je répondrais.
Fund Monica's Lawsuit
8

En C ++, utilisez des constructeurs sans argument. En C, vous ne pouvez pas avoir de constructeurs, utilisez donc soit memsetou - la solution intéressante - les initialiseurs désignés:

struct Snapshot s = { .x = 0.0, .y = 0.0 };
Adrian Panasiuk
la source
Je crois que c'est C, pas C ++. Il ne parviendra pas à compiler sous certains compilateurs C ++. J'ai rencontré l'échec de la compilation sous Cygwin ou MinGW.
2015
3

Je crois que la bonne réponse est que leurs valeurs ne sont pas définies. Souvent, ils sont initialisés à 0 lors de l'exécution des versions de débogage du code. Ce n'est généralement pas le cas lors de l'exécution des versions.

Eric
la source
2
En fait, les versions de débogage se trouvent déjà 0dans ces emplacements en mémoire. Ce n'est pas la même chose que l'initialisation!
Courses de légèreté en orbite le
3

Comme il s'agit d'un POD (essentiellement une structure C), il n'y a pas de mal à l'initialiser de la manière C:

Snapshot s;
memset(&s, 0, sizeof (s));

ou similaire

Snapshot *sp = new Snapshot;
memset(sp, 0, sizeof (*sp));

Je n'irais pas jusqu'à utiliser calloc()dans un programme C ++.

finnw
la source
3
Même chose pour le double; all-bits-zero n'est pas nécessairement 0,0. Cependant, vous pouvez vérifier si vous avez des doubles IEEE754, auquel cas cela doit fonctionner.
MSalters
1

Déplacez les membres du pod vers une classe de base pour raccourcir votre liste d'initialisation:

struct foo_pod
{
    int x;
    int y;
    int z;
};

struct foo : foo_pod
{
    std::string name;
    foo(std::string name)
        : foo_pod()
        , name(name)
    {
    }
};

int main()
{
    foo f("bar");
    printf("%d %d %d %s\n", f.x, f.y, f.z, f.name.c_str());
}
Bruno Martinez
la source