OVH Cloud OVH Cloud

Annuler la construction dans un constructeur

12 réponses
Avatar
PurL
Bonjour,

Je dois faire ceci :

HANDLE h = MaFonction(fichier);
MaClasse *objet;

//en cas de succès de ma fontion
//je créé un objet correspondant
if (h) objet = new MaClasse(h);

//en cas d'echec, je m'arrête là
else return;

Maintenant, je voudrais que ce soit ma classe qui s'occupe d'appeler
MaFonction(...) :

MaClasse *objet;
objet = new MaClasse(fichier);

//si echec alors je sors
if (objet == NULL) return;

Cela implique que dans le constructeur de ma classe, si MaFonction renvoie
0(echec) j'annule la construction de la classe et je renvoie NULL comme
pointeur, est-ce possible ?

La meme question se pose pour le destructeur :
Dans le destructeur, je dois appeler une fonction, si celle-ci echoue, je
voudrais que la destruction soit annulée, comment faire ?

Merci pour votre aide,

PurL.

10 réponses

1 2
Avatar
Matthieu Moy
"PurL" writes:

MaClasse *objet;
objet = new MaClasse(fichier);

//si echec alors je sors
if (objet == NULL) return;


Tu ne peux pas. Le constructeur est appelé après l'allocation de
mémoire.

Il faut remplacer ton constructeur par une méthode statique, qui
n'appelle le constructeur que si tu es sur que la construction va
réussir.

Sinon, tu peux penser aux exceptions. Il y a eu une discussion
ici-même il n'y a pas longtemps.

--
Matthieu

Avatar
kanze
"PurL" wrote in message
news:<c24mgq$4am$...

Je dois faire ceci :

HANDLE h = MaFonction(fichier);
MaClasse *objet;

//en cas de succès de ma fontion
//je créé un objet correspondant
if (h) objet = new MaClasse(h);

//en cas d'echec, je m'arrête là
else return;

Maintenant, je voudrais que ce soit ma classe qui s'occupe d'appeler
MaFonction(...) :


La solution habituelle dans ce cas-là est une fonction usine, c-à-d une
fonction statique qui renvoie un pointeur à une instance nouvellement
allouée.

MaClasse *objet;
objet = new MaClasse(fichier);

//si echec alors je sors
if (objet == NULL) return;

Cela implique que dans le constructeur de ma classe, si MaFonction
renvoie 0(echec) j'annule la construction de la classe et je renvoie
NULL comme pointeur, est-ce possible ?


Non. Des constructeurs n'ont pas de valeur de retour.

Selon le cas, on peut lever une exception dans le constructeur. Dans ce
cas-là, on ne revient pas en séquence, le pointeur n'est jamais écrit,
etc. Donc, quelque chose du genre :

MaClasse* p = NULL ;
try {
p = new MaClass( fichier ) ;
} catch ( MonException& ) {
}

pourrait faire l'affaire. Mais à mon avis, c'est lourd, et je ne vois
pas d'avantage par rapport à une fonction usine.

La meme question se pose pour le destructeur :
Dans le destructeur, je dois appeler une fonction, si celle-ci echoue,
je voudrais que la destruction soit annulée, comment faire ?


Dans ce cas-là, impossible. Un destructeur n'échoit jamais. Même dans le
cas où il lève une exception, l'objet est quand même « détruit ». Dans
une expression de delete, par exemple, la mémoire serait libérée,
exception ou non.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Avatar
kanze
wrote in message
news:...

[...]
La meme question se pose pour le destructeur : Dans le destructeur,
je dois appeler une fonction, si celle-ci echoue, je voudrais que la
destruction soit annulée, comment faire ?


Dans ce cas-là, impossible. Un destructeur n'échoit jamais. Même dans le
cas où il lève une exception, l'objet est quand même « détruit ». Dans
une expression de delete, par exemple, la mémoire serait libérée,
exception ou non.


J'ajouterais que les compilateurs sont pas toujours conforme en ce qui
concerne le comportement quand on quitte un destructeurs par une
exception, et que cet comportement varie d'un compilateur à l'autre.
Donc, par exemple, si je lève une exception dans un destructeur d'un
objet dans un tableau, ni g++ ni Sun CC appelle des destructeurs sur les
éléments non encore detruits, malgré §15.2 : « An objet that is
partially constructed or partially destroyed will have destructors
executed for all of its fully constructed subobjects, that is, for
subobjects for which the constructor has completed execution and the
destructor has not yet begun execution. » (Les éléments d'un tableau
sont bien des sous-objets de l'objet qui est le tableau.) VC++ 6.0 fait
correctement, mais néglige (comme les autres, d'ailleurs) à libérer la
mémoire. Si la norme est moins claire en ce qui concerne la libération
de la mémoire, c'est la seule interprétation raisonable, étant donné
qu'on ne peut pas libérer la mémoire autrement.

Vue les erreurs dans ces compilateurs, c'est encore une raison de plus
de ne jamais quitter un destructeur par une exception.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16


Avatar
PurL
La solution habituelle dans ce cas-là est une fonction usine, c-à-d
une fonction statique qui renvoie un pointeur à une instance
nouvellement allouée.


Je pourrais avoir un exemple ou un lien explicatif d'une fonction usine ?
Pour le reste, j'ai compris la leçon, merci.

PurL

Avatar
Manuel
La solution habituelle dans ce cas-là est une fonction usine, c-à-d
une fonction statique qui renvoie un pointeur à une instance
nouvellement allouée.


Je pourrais avoir un exemple ou un lien explicatif d'une fonction usine ?
Pour le reste, j'ai compris la leçon, merci.

PurL




Bonjour,

exemple:

class MaClasse
{
private:
MaClasse(HANDLE h);
~MaClasse(); // 'virtual' si c'est une classe de base
// ...
public:
// ...

// fonction usine
static MaClasse* Construit(char const* fichier)
{
HANDLE h = MaFonction(fichier);
return h ? new MaClasse(h) : 0;
}

bool Detruit(/* ... */)
{
bool ok = ... ;
if (ok) delete this;
return ok;
}
};

int main()
{

MaClasse* p = MaClasse::Construit("fichier.dat"); // ok

// utiliser p

/*
HANDLE h = 0;
p = new MaClasse(h); // erreur de compilation!
delete p; // erreur de compilation !
*/

if (p->Detruit(/*...*/)) // ok
// detruit, ne plus utiliser p
else
// pas detruit, encore utiliser p
// ...
return 0;
}

--

- Manuel
to reply, swap the name with the domain.


Avatar
Etienne Rousee
"Manuel" a écrit ...
if (ok) delete this;


Ah ! Je me posais la question.
Ce n'est pas risqué de faire un delete this ?
C'est un peu comme scier la branche sur laquelle
on est assis, vu qu'on est encore dans le classe.

Etienne

Avatar
Manuel
"Etienne Rousee" a écrit dans le message de
news:c27sjd$4fe$

"Manuel" a écrit ...
if (ok) delete this;


Ah ! Je me posais la question.
Ce n'est pas risqué de faire un delete this ?


Oui, c'est risqué si on ne sait pas ce qu'on fait.
Il ne faut pas accéder au membres de la classe,
donnée ou fonctions, après un "delete this".
Concrètement, c'est la "dernière" operation à faire.

C'est un peu comme scier la branche sur laquelle
on est assis, vu qu'on est encore dans le classe.


Une fonction membre n'est pas "dans la classe"
comme le serait une donnée membre...
Après tout, ce n'est pas très différent de :

struct Classe {
// ...
};

bool Detruire(Classe* This)
{
bool ok = ...;
if (ok) delete This;
return ok;
}

Le risque est le même ici si on deréférence le
pointeur "This" après le "delete This", sinon
c'est sans danger.

--

- Manuel
to reply, swap the name with the domain.


Avatar
PurL
Merci pour ton intervention, cela est tres instructif.

PurL
Avatar
kanze
"PurL" wrote in message
news:<c27kml$2kv$...

La solution habituelle dans ce cas-là est une fonction usine, c-à-d
une fonction statique qui renvoie un pointeur à une instance
nouvellement allouée.


Je pourrais avoir un exemple ou un lien explicatif d'une fonction
usine ? Pour le reste, j'ai compris la leçon, merci.


Achête-toi le livre « Design Patterns : Elements of Reusable
Object-Oriented Sofware », de Gamma, Helm, Johnson et Vlissides (ISBN
0-201-63361-2). C'est un des must. (Il existe en traduction, mais
d'après ce qu'on me dit, la traduction n'est pas très bonne.)

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16


Avatar
Etienne Rousee
a écrit ...
(Il existe en traduction, mais d'après ce qu'on me dit,
la traduction n'est pas très bonne.)


Je la trouve pas si mauvaise que ça.
Par contre, il y manque, me semble-t-il, le pattern "Mutation".

Etienne

1 2