[C++]Détruit ou pas ?

Bonjour tout le monde !

J’ai un gros doute qui m’assaille subitement en pleine phase de programmation.

J’ai une classe « Random » qui me génère des nombres aléatoires; une classe « Foo » qui contient un objet dice pour chaque instanciation de cette classe. De plus, « Foo » contient une (plusieurs) listes d’objets de type « Bar », qui seront créés/détruits en cours d’exécution.

[code]#include « random.h »
#include « bar.h »

class Foo {
private:
Random dice;
list<Bar *> my_bar;
};[/code]

Puisque les objets de type « Bar » doivent pouvoir appeler « Foo::dice » (et non avoir chacun un générateur indépendant), j’ai implémenté la chose de la manière suivante :

[code]class Bar {
private:
Random ref_to_dice;
Bar();
public:
Bar(Random & rand) : ref_to_dice(rand) {

};
~Bar() {
};
};

Foo::createBar() {

Bar * B = new Bar(dice);
my_bar.push_back(B);

}[/code]

Tout ça semble fonctionner correctement (pas vraiment testé en fait), mais je viens de me poser la question suivante : comme les objets « Bar » peuvent etre détruits, est-ce que « Foo::dice » sera détruit dès le premier appel au destructeur (appel implicite, je ne demande rien moi) ? Ce qui ne serait pas pratique puisque j’en aurai encore besoin plus tard.

Je vois déjà des solutions si c’est le cas :

  1. Je peux réutiliser les objets « Bar » et du coup ne pas les détruire; à éviter je suppose
  2. « dice » en variable globale : j’évite les variables globales le plus possible; en plus, il peut y avoir plusieurs Foo, et j’aimerais bien garder un « dice » différent par « Foo » (pas obligatoire cependant)
  3. Un pointeur « Random * ref_to_dice » dans « Bar », à la place de la référence; il serait détruit en le mettant à NULL, mais j’en ai pas envie (me demandez pas pourquoi, y’a pas de réelle explication si ce n’est pour éviter « -> » :stuck_out_tongue: )
  4. Mettre « ref_to_dice » en « static », mais je vois pas comment l’initialiser dans ce cas
  5. Utiliser le « rand » de C, ce qui revient un peu au point 2)
  6. Y’a plus simple ? Me gourre-je ?

C’est pas urgent, mais j’aimerais bien apprendre quelque chose pour quand meme…

[code]class Bar {
private:
Random ref_to_dice;
Bar();
public:
Bar(Random & rand) : ref_to_dice(rand) {

};
~Bar() {
};
};

Foo::createBar() {

Bar * B = new Bar(dice);
my_bar.push_back(B);

}[/code]

Bon deja je pense qu’il faut éviter ca
Ta déclaration

Random ref_to_dice;

fait qu’a l’appel du constructeur a mon avis

Bar(Random & rand) : ref_to_dice(rand) {

Tu passes dans le constructeur de copie (implicite) donc tu as un dé différent à chaque Bar :stuck_out_tongue:
(sans compter que la destruction dedits Random risque de faire buguer si tu n’as pas ecrit le constructeur de copie correctement)

Random ref_to_dice; doit être changer en
Random& ref_to_dice;

Ca ne change rien au code du constructeur et tu as le même dé pour tous les Bar

Ensuite ce qui a été construit doit être détruit et par celui qui a construit (je sais c’est l’idéal)

Vu que c’est Foo qui a creer Bar dans une méthode c’est à lui de le détruire dans une méthode symétrique DeleteBar. Méthode où tu dois détruire CORRECTEMENT les éléments de ta liste (la liste container en elle même sera détruite implicitement mais pas ce qui est à l’intérieur) … j’écris ca en étant pas un pro des STL mais y a aucune raison que la destruction de la liste détruise les éléments internes surtout si ceux ci sont sous forme de pointeur.

C’est une méthode que tu devras certainement appeler à la destruction pour nettoyer ton objet.

Ouep, tout comme Zoulou, c’est une référence que tu veux, pas une copie de l’objet. La destruction d’une référence ne détruit pas l’objet référencé.

Par contre Zoulou, quand tu dis “y a aucune raison que la destruction de la liste détruise les éléments internes surtout si ceux ci sont sous forme de pointeur” c’est partiellement faux, quand on détruit un container STL, ça détruit tout ce qui se trouve dedans. Maintenant, si ça contient des pointeurs, ça ne détruit pas les objets pointés, là t’as raison.

Oki doki !

Donc il suffit que je le transforme en VRAIE référence (avec la jolie esperluette) et ça me le détruira pas. C’était l’idée de base que j’avais, mais effectivement j’aurais du vérifier s’il s’agissait d’une copie ou d’une référence (n’ayant pas défini de constructeur par copie j’ai betement cru qu’il n’en créait pas un implicitement… :stuck_out_tongue: ).

Bon bon bon, je vais pouvoir continuer à programmer en étant un peu moins bete que toute à l’heure, merci beaucoup :stuck_out_tongue:

Sisi, le contructeur par copie est implicitement défini, et ça vaut parfois de jolies surprises… Par contre, à partir du moment où tu auras une référence comme membre de ta classe, tu vas te choper des warnings comme quoi ce constructeur par copie ne pourra pas être défini implicitement (vu qu’on ne peut pas assigner une référence).

Pourquoi un dice par instance de Foo ? A priori ce ne serait pas gênant de n’en avoir qu’un, et ça me semble être un cas d’école pour un singleton (instance unique et accessible de partout).

[code]class Dice: public Random {

public:
Dice(){
if (Unique != NULL){
// erreur / exception
}
}

static Dice & Instance() {
if (Unique == NULL){
Unique = new Dice();
} else {
return *Unique;
}
}

private:
static Dice* Unique = NULL;
};[/code]

Ça fait un bail que je n’ai pas fait de C++, donc ce post au aussi pour but de faire tester mon niveau :stuck_out_tongue:

On écrirait plutôt

[code]class Foo
{

private:
static Dice m_Dice;

}

Dice Foo::m_Dice;[/code]

Attention dans certains cas l’initialisation des objets statiques peu poser des problèmes.

Ouep, par expérience je fuis comme la peste les objets statiques à partir du moment où il sont un peu plus compliqués qu’une string ou un struct de POD. Parce que quand plus tard on essaie de faire du memory management pour le debugging de leaks ou le profiling ça fout un souk pas possible.

edit: ça peut se dire plus simplement par “si un objet touche à la heap dans son constructeur/destructeur, faut pas le mettre en statique”