web-dev-qa-db-fra.com

Moyen approprié pour initialiser les structures C ++

Notre code implique une structure POD (Plain Old Datastructure) (c'est une structure de base c ++ qui contient d'autres structures et variables POD qui doivent être initialisées au début.)

Basé sur ce que j'ai l , il semble que:

myStruct = (MyStruct*)calloc(1, sizeof(MyStruct));

devrait initialiser toutes les valeurs à zéro, comme le fait:

myStruct = new MyStruct();

Cependant, lorsque la structure est initialisée de la deuxième manière, Valgrind se plaint plus tard: "le saut ou le déplacement conditionnel dépend de valeurs non initialisées" lorsque ces variables sont utilisées. Ma compréhension est-elle imparfaite ou Valgrind génère-t-il des faux positifs?

69
Shadow503

En C++, les classes/structures sont identiques (en termes d’initialisation).

Une structure non POD peut également avoir un constructeur pour pouvoir initialiser des membres.
Si votre structure est un POD, vous pouvez utiliser un initialiseur.

struct C
{
    int x; 
    int y;
};

C  c = {0}; // Zero initialize POD

Sinon, vous pouvez utiliser le constructeur par défaut.

C  c = C();      // Zero initialize using default constructor
C  c{};          // Latest versions accept this syntax.
C* c = new C();  // Zero initialize a dynamically allocated object.

// Note the difference between the above and the initialize version of the constructor.
// Note: All above comments apply to POD structures.
C  c;            // members are random
C* c = new C;    // members are random (more officially undefined).

Je pense que valgrind se plaint car c’était comme ça que C++ fonctionnait. (Je ne sais pas exactement quand C++ a été mis à niveau avec la construction par défaut à initialisation nulle). Votre meilleur pari est d'ajouter un constructeur qui initialise l'objet (les structures sont des constructeurs autorisés).

En note de côté:
Beaucoup de débutants essaient de valoriser init:

C c(); // Unfortunately this is not a variable declaration.
C c{}; // This syntax was added to overcome this confusion.

// The correct way to do this is:
C c = C();

Une recherche rapide sur "La plupart des analyses vexantes" fournira une meilleure explication que moi.

102
Martin York

D'après ce que vous nous avez dit, cela semble être un faux positif chez Valgrind. La syntaxe new avec () devrait initialiser l'objet par valeur, en supposant qu'il s'agisse d'un POD.

Est-il possible qu'une sous-partie de votre structure ne soit pas réellement un POD et que cela empêche l'initialisation attendue? Êtes-vous en mesure de simplifier votre code dans un exemple postable qui signale toujours l'erreur valgrind?

Sinon, peut-être que votre compilateur n'initialise pas réellement les structures POD.

Dans tous les cas, la solution la plus simple consiste probablement à écrire le ou les constructeurs nécessaires pour les structures/sous-parties.

2
Mark B

J'écris du code de test:

#include <string>
#include <iostream>
#include <stdio.h>

using namespace std;

struct sc {
    int x;
    string y;
    int* z;
};

int main(int argc, char** argv)
{
   int* r = new int[128];
   for(int i = 0; i < 128; i++ ) {
        r[i] = i+32;
   }
   cout << r[100] << endl;
   delete r;

   sc* a = new sc;
   sc* aa = new sc[2];
   sc* b = new sc();
   sc* ba = new sc[2]();

   cout << "az:" << a->z << endl;
   cout << "bz:" << b->z << endl;
   cout << "a:" << a->x << " y" << a->y << "end" << endl;
   cout << "b:" << b->x << " y" << b->y <<  "end" <<endl;
   cout << "aa:" << aa->x << " y" << aa->y <<  "end" <<endl;
   cout << "ba:" << ba->x << " y" << ba->y <<  "end" <<endl;
}

g ++ compiler et exécuter:

./a.out 
132
az:0x2b0000002a
bz:0
a:854191480 yend
b:0 yend
aa:854190968 yend
ba:0 yend
1
Yadong

Puisqu'il s'agit d'une structure POD, vous pouvez toujours le memset à 0 - c'est le moyen le plus simple d'initialiser les champs (en supposant que ce soit approprié).

0
Scott C Wilson

Vous devez initialiser les membres que vous avez dans votre structure, par exemple:

struct MyStruct {
  private:
    int someInt_;
    float someFloat_;

  public:
    MyStruct(): someInt_(0), someFloat_(1.0) {} // Initializer list will set appropriate values

};
0
ralphtheninja