initialisation de structure

initialisation de structure - C++ - Programmation

Marsh Posté le 01-12-2011 à 18:56:01    

Bonjour
Comment initialiser en c++ tous les champs d'une classe à zéro à la construction ou après (sans le faire explicitement sur les 1000000 variables), les pointeurs à NULL et les vector à aucun élément?
 
J'avais une structure c conventionnelle, je faisais un memset à zéro et tout se passait bien.
J'ai rajouté un std::vector dedans et je prends un segfault pour une raison que j'ignore...  :??:  
 
merki

Reply

Marsh Posté le 01-12-2011 à 18:56:01   

Reply

Marsh Posté le 01-12-2011 à 20:20:04    

J'ai pas l'explication complète mais il me semble que c'est un peu comme si tu faisait :
 

Code :
  1. int a;
  2. &a = 0;


 
Mais bon, on va attendre un explication plus éclairée.


---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 01-12-2011 à 21:38:43    

En C, un struct est juste une zone mémoire qui contient des données (et des zones de padding en cas d'alignement).
En C++, un struct, c'est simplement une classe dont les données ont un accés public par défaut (alors qu'il est privé pour une classe).
On peut très bien faire de l'héritage de struct en C++:
struct A { };
struct B : A { };
struct C : B { };
Donc comme c'est une classe, faire un memset à 0 est pas du tout une bonne idée.
Si tu veux initialiser les champs d'un struct à 0, il faut faire comme tu ferais pour une classe.
A+,


Message édité par gilou le 01-12-2011 à 21:40:54

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 01-12-2011 à 21:42:08    

explicitement membre par membre?  :sweat:

Reply

Marsh Posté le 01-12-2011 à 21:46:02    

Exactement comme pour une classe.
Mais bon, est il normal qu'une classe ait des centaines de membres (non dérivés)...
 
Donc c'est la qu'il est bon de faire la distinction entre
MaStruct s; // pas d'initialisation
MaStruct s = {}; // initialisation à 0 des membres
En supposant que tu n'as pas défini de constructeur pour ton struct, ce que ton commentaire me laisse supposer.
 
De toute façon, un memset à 0 d'un struct, même en C, c'est pas une bonne idée.
Si certains membres sont des doubles , il n'est pas certain que tous les bits à 0 corresponde à la valeur 0.0 (c'est le cas s'ils sont à la norme IEEE754  néanmoins)
A+,


Message édité par gilou le 01-12-2011 à 21:59:32

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 01-12-2011 à 21:59:25    

Je suis obligé d'avoir plein de membres, c'est une structure qui contient toutes les informations d'une journée... Et si je n'écris rien dans le champs il faut qu'il soit à une valeur certaine...
 
 
j'ai trouvé ça qui peut être sympa, mais ça va encore faire deux fois plus de code...
 
 
struct MY_STRUCT
{
    int n1;
    int n2;
};
 
class CMyStruct : public MY_STRUCT
{
public:
    CMyStruct():MY_STRUCT() { }
};
 
 
Initialiser tout à la main c'est horrible

Reply

Marsh Posté le 01-12-2011 à 22:00:36    

un membre de type std::vector<...> sera automatiquement initialisé à 0 élément par le compilo, pas besoin de le faire toi-même.
 
En C, les structures sont des aggrégat d'octets, libre à toi de tout mettre à zero.
En C++ une classe doit être inialisée par son constructeur (et lui seul) ainsi que ses classes de base et ses membre. Remplir à la main avec des zero à coup de memset c'est pas compatible avec le C++, ça c'est pour le C pur.
Le compilateur initialise par défaut tout avec leur constructeur par defaut. Et le constructeur par défaut d'un std::vector<...>, c'est vector à 0 élément.
 

Code :
  1. struct T
  2. {
  3.    std::vector< int > v;
  4. };
  5. T t;
  6. t.v.size() == 0 // vrai

Reply

Marsh Posté le 01-12-2011 à 22:00:42    

Euh, GrosBocdel, si ton struct n'a pas de constructeur, je t'ai donné la solution en une ligne dans mon post, hein...
 
struct MyStruct  
{  
    int n1;  
    int n2;  
};  
 
MyStruct s = {}; // initialise s.n1 et s.n2 à 0
 
A+,


Message édité par gilou le 01-12-2011 à 22:03:47

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 01-12-2011 à 22:02:08    

ta solution qui consiste à dériver d'une structure pur C (une P.O.D. pour les connaisseur) je la trouve très élégante.
 
Et c'est mieux que d'initialiser chaque membre à la main dans le constructeur.
edit pour gilou : appeler explicitement le constructeur d'une POD revient à faire un ={} donc sa solution est plutôt bien.


Message édité par jesus_christ le 01-12-2011 à 22:03:14
Reply

Marsh Posté le 01-12-2011 à 22:05:03    

gilou: oui. En fait j'ai une structure de base qui vient du C et sur laquelle j'ai rajouté des std::vector.
Il problème venait de là, à la base.

Reply

Marsh Posté le 01-12-2011 à 22:05:03   

Reply

Marsh Posté le 01-12-2011 à 22:06:29    

jesus_christ, parce que ça lui permet d'avoir un constructeur qui fait implicitement tout le boulot? oui en effet.
A+,


Message édité par gilou le 01-12-2011 à 22:06:57

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 01-12-2011 à 22:14:00    

Pourquoi tous les bits à zéro ça ferait pas zéro sur un float?
Sur une archi particulière?

Reply

Marsh Posté le 01-12-2011 à 22:31:14    

sur une possible archi très très exotique.
Sur tout CPU un peu moderne et pas trop bizarre le zéro est exprimé avec que des 0 bit-à-bit. Le standard IEEE-754 (la norme des flottants) le dit, mais le standard C ne le garantit pas.
 
donc gilou a raison, le memset(.., 0) c'est un mauvais style et c'est pas portable. Le ={} ou le constructeur à la C++ c'est mieux.
 

Code :
  1. struct T { ... only C-like members... };
  2. T t = {}; // bien
  3. T t = T(); // bien aussi
  4. T t; memset( &t, 0, sizeof t ); // pas bien

Reply

Marsh Posté le 01-12-2011 à 22:35:13    

GrosBocdel a écrit :

Pourquoi tous les bits à zéro ça ferait pas zéro sur un float?
Sur une archi particulière?

Les floats, il y a eu tout un tas d'implémentations selon les bécanes. Les normalisations IEEE, c'est relativement récents. Et apparement, il y a eu le cas ou tous les bits à 0 ne signifiait pas 0 (ou en tout cas, c'est un mythe assez tenace).
A+,


Message édité par gilou le 01-12-2011 à 22:36:42

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 02-12-2011 à 08:43:07    

et donc si mes structures sont allouées dynamiquement, je suis foutu? initialisation explicite?
 

Reply

Marsh Posté le 02-12-2011 à 09:57:23    

pourquoi foutu ?
Le truc du ={} ou le constructeur C++ ça marche très bien et ça met tout à zero, portable.
Sinon tu peux toujours mettre les membres à zero à la main. C'est juste moins joli.
 

Code :
  1. struct T { float value; };
  2. T t;
  3. t.value = 0;

Reply

Marsh Posté le 02-12-2011 à 11:54:04    

oui mais avec T *t=new T;
?
 
J'ai des stuctures qui sont des aggrégats d'autres structures, je m'arrache les cheveux.
Faut vraiment que tout soit à zéro car j'ai des champs que je ne sais pas remplir (je n'ai pas leur signification, les structures ne viennent pas de moi) mais que je sauvegarde quand même!


Message édité par GrosBocdel le 02-12-2011 à 11:54:20
Reply

Marsh Posté le 02-12-2011 à 12:19:51    

Je rate un truc ou ça ne marche pas cette histoire de constructeur c++ appelant celui de la struct ?
 

$ cat class_struct.cpp
 
#include <iostream>
using namespace std;
 
struct MyStruct {
    int n1;
    int n2;
};
 
class CMyStruct : public MyStruct {
    public:
        CMyStruct() : MyStruct() {  
            cout << "built!" << endl;
        }
};
 
int main() {
    CMyStruct toto;
    cout << toto.n1 << endl;
    cout << toto.n2 << endl;
    return 0;
}


 

$ g++ -Wall class_struct.cpp -o toto
$ ./toto.exe  
built!
2674688
1629774854


 


---------------
Il y a autant d'atomes d'oxygène dans une molécule d'eau que d'étoiles dans le système solaire.
Reply

Marsh Posté le 02-12-2011 à 13:41:21    

le code n'était pas de moi, mais ici j'ai bien:
built!
0
0

Reply

Marsh Posté le 02-12-2011 à 14:27:40    

Avec le compilo c++ de Digital Mars
built!
1310640
4332693
 [:chacal_one333]  
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 02-12-2011 à 14:52:09    

ok, je me rends, j'initialise à la main

Reply

Marsh Posté le 02-12-2011 à 15:09:35    

Euh non, je viens de voir que le compilo de digital mars accepte pas ceci:
 

Code :
  1. #include <iostream>
  2. using namespace std;
  3. struct MyStruct {
  4.     int n1;
  5.     int n2;
  6. };
  7. int main() {
  8.     MyStruct toto = {};
  9.     cout << toto.n1 << endl;
  10.     cout << toto.n2 << endl;
  11.     return 0;
  12. }


 
qui passe très bien avec mingw (je viens de tester), donc c'est peut être un problème du compilo de Digital Mars.
Noter que le code précédent donne ici 0, 0
tandis qu'avec mingw, l'encapsulation dans une classe donne
built!
4246592
2147348480
 :pt1cable:  
A+,
 
 


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 02-12-2011 à 15:15:35    

Xavier_OM a écrit :

Je rate un truc ou ça ne marche pas cette histoire de constructeur c++ appelant celui de la struct ?
 

$ g++ -Wall class_struct.cpp -o toto
$ ./toto.exe  
built!
2674688
1629774854


 


 
Bug apparemment fixe avec gcc 4.4 (il est present ici avec gcc 4.3, pas avec gcc 4.4).
 
Ca ne m'etonnerait pas que sur ce point il y ait eu des problemes d'interpretations pour savoir quand il fallait initialise et quand on pouvait laisser non initialise.


---------------
The truth is rarely pure and never simple (Oscar Wilde)
Reply

Marsh Posté le 02-12-2011 à 15:42:50    

Un Programmeur a écrit :


 
Bug apparemment fixe avec gcc 4.4 (il est present ici avec gcc 4.3, pas avec gcc 4.4).
 
Ca ne m'etonnerait pas que sur ce point il y ait eu des problemes d'interpretations pour savoir quand il fallait initialise et quand on pouvait laisser non initialise.

avec la toute dernière version de mingw que je viens d'installer, donc port de gcc 4.6.1
built!
7
2147340288
 :whistle:  
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 02-12-2011 à 16:19:26    

Je viens de faire comme toi, upgrade de cygwin de  
    gcc version 4.3.4 20090804 (release) 1 (GCC)  
vers
    gcc version 4.5.3 (GCC)  
 
Et maintenant j'ai 0 (comme avec Visual Studio)


---------------
Il y a autant d'atomes d'oxygène dans une molécule d'eau que d'étoiles dans le système solaire.
Reply

Marsh Posté le 02-12-2011 à 17:14:46    

:o J'ai deux versions, et je viens de voir que c'est pas la bonne qui est appelée par défaut. Je vais mettre mon PATH a jour.
 
Avec la bonne version:
 
built!
0
0
 [:hill]  
A+,


Message édité par gilou le 02-12-2011 à 17:40:03

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 04-12-2011 à 10:36:45    

Le standard dit que ça doit faire 0 0 car MyStruct est une POD. Certains compilos peuvent ne pas respecter ce standard.
 
Ne pas confondre :

Code :
  1. T *t=new T;


avec

Code :
  1. T *t=new T();


 
Dans le 2e cas, si T est une POD, ça remplit de zéro. Pas dans le premier cas.

Reply

Marsh Posté le 04-12-2011 à 10:50:32    

Oui, mais de toute façon, je vois que le compilo de Digital Mars à l'air à la traine, vu ce qu'il n'a pas fait sur un simple struct.
L'auteur se concentre peut être plus sur son langage D, au vu du peu d'évolution des binaires de son compilo C++ depuis 2 ans.
A+,


Message édité par gilou le 04-12-2011 à 10:50:53

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 04-12-2011 à 12:33:45    

jesus_christ a écrit :

Le standard dit que ça doit faire 0 0 car MyStruct est une POD. Certains compilos peuvent ne pas respecter ce standard.
 
Ne pas confondre :
 

Code :
  1. T *t=new T;


avec

Code :
  1. T *t=new T();


Dans le 2e cas, si T est une POD, ça remplit de zéro. Pas dans le premier cas.


 
chauds les marrons

Reply

Marsh Posté le 04-12-2011 à 12:56:23    

Code :
  1. #include <iostream>
  2. using namespace std;
  3. typedef struct {
  4.     int n1;
  5.     int n2;
  6. } MyStruct;
  7. int main()
  8. {
  9.   MyStruct m0;
  10.   MyStruct *ma=new MyStruct;
  11.   MyStruct *mb=new MyStruct();
  12.   std::cout<<"m0="<<m0.n1<<" "<<m0.n2<<std::endl;
  13.   std::cout<<"ma="<<ma->n1<<" "<<ma->n2<<std::endl;
  14.   std::cout<<"mb="<<mb->n1<<" "<<mb->n2<<std::endl;
  15.   delete ma;
  16.   delete mb;
  17.   return 0;
  18. }


 
C'est le hasard alors si les champs de ma sont à zéro?

Reply

Marsh Posté le 05-12-2011 à 10:51:09    

c'est l'implémentation de ton compilo et/ou OS.
Par exemple sous Windows NT+ (2000, xp et plus) un new remplit de zéro, mais pas sous win98. Ça dépend aussi du mode débug/release.
Et cette subtilité n'est même pas toujours bien respectée par les compilos.

Reply

Marsh Posté le 05-12-2011 à 11:04:07    

Ha voilà où j'avais déjà vu ça.
J'avais du code vc6 qui fonctionnait en débug et crashait en release.
Il y avait des variables non initialisées. En débug il les mettait à zéro et pas en release.
C'est vrai

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed