Forum |  HardWare.fr | News | Articles | PC | Prix | S'identifier | S'inscrire | Shop Recherche
1838 connectés 

  FORUM HardWare.fr
  Programmation
  C++

  [C++] Questions sur "new" et les arguments d'un constructeur

 



 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[C++] Questions sur "new" et les arguments d'un constructeur

n°2214919
Profil sup​primé
Posté le 04-01-2014 à 00:20:20  answer
 

Bonsoir :jap: ,
Je poste parce que je me pose des questions sur le sujet de l'utilisation d'un constructeur et l'utilisation de new (alloc dynamique) en même temps.
(Ca fait pas longtemps que j'ai fait du C++, mais j'ai fait du C, du Java et d'autres trucs avant)

 

J'ai en gros la classe suivante graph qui est une matrice 2D de booléen (les valeurs représentes les liens entre noeuds du graphe)

 
Code :
  1. class graph{
  2. private:
  3.     bool** edges;
  4.     int size;
  5. public:
  6.     graph(int size):size(size){
  7.         edges = new bool*[size];
  8.         for (int i = 0; i < size; i++){
  9.             edges[i] = new bool[size];
  10.         }
  11.     }
  12.     ~graph(){
  13.         for(int i = 0; i < size; ++i) {
  14.             delete [] edges[i];
  15.         }
  16.         delete [] edges;
  17.     }
 

Je suis passé par 2 boucles dans le constructeur parce qu'apparemment, on ne peut pas utiliser new avec un tableau multi-dimensionnel.
Y a une raison ? :jap:

 

Ensuite, je me demande :
A l'intérieur du constructeur, j'utilise l'allocation dynamique.

 

Mais dans mon main, avec l'instruction suivante

Code :
  1. graph graph1 (4);


Je fais une allocation statique, non ?
Du coup, il est ou mon objet au final ? Dans le stack ou dans le heap ?

 

Enfin, on en arrive à ma vraie question :
Quand je tente de faire par exemple : graph graph1 = new graph(5); ça me renvoie :
invalid conversion from 'graph*' to 'int' [-fpermissive])

 

Apparemment, new appelle pas de constructeur (faudrait que j'overloade new ? Donc que je fasse un constructeur par défault qui ferait de l'alloc statique et un new qui ferait l'alloc dynamique ? Je suis un peu paumé là.)

 

Au final, quelle est la bonne méthode pour initialiser mon tableau de liens si je veux allouer dynamiquement un graph ?
Je fais une méthode setEdges(int size) ?

 

C'est propre comme code de faire un constructeur qui peut laisser un attribut pointé dans le vide ?

 

Merci pour l'aide, et désolé pour les questions de noobs, je débarque en C++ :jap:
(J'avais fait de la POO en Java, mais je me posais pas de questions sur la gestion de la mémoire, j'ai commencé à m'en préoccuper quand j'ai fait du C).


Message édité par Profil supprimé le 04-01-2014 à 10:47:15
mood
Publicité
Posté le 04-01-2014 à 00:20:20  profilanswer
 

n°2214929
29jm
Posté le 04-01-2014 à 13:19:40  profilanswer
 

Concernant ta "vraie question", tu ne peut pas faire ça car new renvoit un pointeur sur l'objet alloué, donc tu dois faire :

Code :
  1. graph* graph1 = new graph(5);


Et tu accèderas aux méthodes en utilisant 'graph1->setEdge()' et à l'objet lui même (et pas au pointeur) en faisant '*graph1' (ex: "(*graph1).setEdge()" )
new appelle le constructeur approprié, je crois que t'as pas à te soucier de ça.
 
Pour l'allocation du tableau 2D c'est parce que tu alloue des emplacements contenant des pointeurs (1ère dimension), qu'il faut faire pointer vers des emplacement valides (je pense que tu trouveras plus clair sur stackoverflow). Une autre solution est de faire un vector de vector de bool, comme ça y'a pas d'allocation explicite et pas de pointeurs.
 
Sinon pour l'emplacement de ton objet en mémoire, je laisse quelqu'un de plus expérimenté répondre.

n°2215010
Farian
Posté le 04-01-2014 à 22:50:34  profilanswer
 

Bonjour !
 
Dans l'exemple que vous citez, ce qui est dit est que si vous redéfinissez l'opérateur new dans une classe, il ne doit faire que l'allocation de la mémoire nécessaire à l'objet (pour faire votre propre gestion de la mémoire).
 
En revanche quand vous faites "toto = new Objet(x,y)",  les opérations suivantes sont effectuées :  
 * Appel de l'opérateur new de la classe Toto
 * Si la classe Toto est une classe fille, appel du constructeur de la classe mère
 * Appel du constructeur qui prend les paramètres x et y
 
Sinon, non, ce n'est pas propre de laisser un attribut (surtout un pointeur !) non initialisé, car aucune valeur par défaut n'est utilisée, la valeur de l'attribut sera celle de la case mémoire correspondante au moment où l'allocation est faite (quoique, en mode "debug", certains compilateurs initialisent ces attributs par défaut, mais pas en "release" ).
 
Bonne continuation, et bon courage pour la gestion de la mémoire, ce n'est pas toujours facile, on peut rapidement faire planter les programmes, mais on a vraiment la main, surtout quand on brasse pas mal d'allocations / désallocations, par rapport au Java où le GC fait (à peu près) ce qu'il veut ...
 
Sinon, sauf erreur de ma part, quand vous faites "graph graph1(4)", l'objet graph est alloué sur la pile, tandis que les "new" qui sont faits dans le constructeur sont alloués sur le tas.  
 
Je laisse des vrais experts corriger mes dires :)
 
Bonne continuation !


Message édité par Farian le 04-01-2014 à 22:50:46
n°2216416
user89
Posté le 17-01-2014 à 14:38:33  profilanswer
 

Bonjour,
 
Comme d’autres ont déjà répondu à ta question, je me permets de ne pas y répondre et simplement de te suggérer de ne jamais utiliser new lorsque l’on peut s’en passer -- c’est-à-dire quasiment tout le temps.
 
Dans l’exemple que tu donnes, par exemple, l’utilisation de std::vector s’impose pour allouer dynamiquement un tableau. Comme tu viens du C, l’abandon du réflexe de l’allocation manuelle est perturbante au début, mais libératoire au final.

n°2216432
tpierron
Posté le 17-01-2014 à 15:19:32  profilanswer
 

user89 a écrit :

Comme d’autres ont déjà répondu à ta question, je me permets de ne pas y répondre et simplement de te suggérer de ne jamais utiliser new lorsque l’on peut s’en passer -- c’est-à-dire quasiment tout le temps.


 
Mouais, une petite explication du pourquoi il faut éviter new, ça ne serait peut-être pas trop mal, nan ? La raison principale, c'est parce que ça ne fait pas bon ménage du tout avec les exceptions. Les symptomes typiques sont fuite mémoire et plantage plus que probable.
 
Par exemple dans ton code, si un new de ta boucle interne de ton constructeur retourne une exception, ton objet sera dans un état instable, tu seras incapable de déterminer quoi libérer. Au mieux fuite mémoire, au pire, plantage.
 
Le problème se pose aussi à l'utilisation. Avec un code du gerne :

Code :
  1. graph * graph1 = new graph(5);
  2.  
  3. /* Code travaillant sur graph1 */
  4.  
  5. delete graph1;


 
Si le code entre l'allocation et le delete retourne une exception non traitée dans la fonction => fuite mémoire. Avec un exemple aussi simple, c'est relativement évident. Lorsque les appels de fonctions commencent à s'empiler, il y intérêt à être prudent, si tu ne veux rajouter de try/catch tous les 2 lignes de codes.
 
Tandis qu'écrit de la sorte :
 

Code :
  1. graph graph1(5);
  2.  
  3. /* Code travaillant sur graph1 */


 
Si une exception se déclenche, ton destructeur sera appelé, pas besoin de pourrir le code avec try/catch, même pas besoin de delete, quelque soit la condition de retour de ta fonction. Ta variable ici, sera déclarée sur la pile (les champs edges et size), mais tes vecteurs seront bien alloués dynamiquement.
 

n°2216508
Thutur
Why so serious ? Higniiiihaha
Posté le 17-01-2014 à 19:07:50  profilanswer
 

De plus, utiliser new est une opération qui prend du temps (appels system) donc si tu peux t'en passer, faut pas hésiter.
 
Cela dit, ca reste indispensable dans tout de même pas mal de cas (par exemple lorsque que l'on utilise une interface ou une classe abstraite).

n°2216527
user89
Posté le 17-01-2014 à 21:44:03  profilanswer
 

tpierron a écrit :


Mouais, une petite explication du pourquoi il faut éviter new, ça ne serait peut-être pas trop mal, nan ? La raison principale, c'est parce que ça ne fait pas bon ménage du tout avec les exceptions.


 
La vrai raison principale est que chaque 'new' doit être suivi d'un 'delete', et qu'il existe de multiples façon d'oublier de le faire. Les exceptions en sont une, mais c'est loin d'être la seule, et c'est à mon avis pas celles qui sont les plus difficiles ni les plus courantes. Demoderateur venant du C, il doit bien connaître le problème des fuites mémoires alors même que le C ne possède pas d'exception.
 
Par ailleurs, même lorsque l'on travaille avec des classes abstraites, on peut (doit?) s'abstenir de faire des new et utiliser des pointeurs nu lorsqu'on le peut.


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C++

  [C++] Questions sur "new" et les arguments d'un constructeur

 

Sujets relatifs
Aide pour un petit programme en CErreur compilation sur prog en C
Programmation en C[C] Programmer "Jeu des batons" par récursivité
[C]Détection de fin de fichier...[C]Chaine qui ne s'affiche pas...
télécharger et installer C++C++ et procédure stockées MySql
Novice en langage C ! HELP![C] Tirage de lettre et probabilité
Plus de sujets relatifs à : [C++] Questions sur "new" et les arguments d'un constructeur


Copyright © 1997-2018 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR