Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

destruction d'un Singleton Pattern : Static ou non Static

18 réponses
Avatar
requinham
Bonjour,

je parlais avec un amis sur la declaration de la fonction qui se
chargera de la destruction de notre instance unique destroy()

en fait est ce que c'est n=E9cessaire de la d=E9clarer static au niveau
conceptuel. car au niveau codage elle ne d=E9range pas vue qu'elle sera
la derni=E8re =E0 s'ex=E9cuter donc elle retournera la main =E0 un autre ob=
jet
ou fonction diff=E9rente de l'instance ?

A votre avis comment =E7a se fait ?

10 réponses

1 2
Avatar
requinham
On 17 fév, 09:03, Mickaël Wolff wrote:
requinham a écrit :

> en fait est ce que c'est nécessaire de la déclarer static au niveau
> conceptuel.

   Oui, sinon on risque de se poser des questions sur le pourquoi de ce
fonctionnement.

--
Mickaël Wolff aka Lupus Michaelishttp://lupusmic.org



A vrai dire, le fait de la déclarer static n'a pas de sens car pouvoir
fair un appel statique à destroy n'aura pas de sens tant qu'il n'y a
pas de singleton en memoire et dans le cas où il y en a on peut
l'appeler à partir du singleton exple : A::getInstance()->destroy()
sans problème vue que c'est la derniere instruction appelé dans la vie
du singleton.
Avatar
Mickaël Wolff
requinham a écrit :
en fait est ce que c'est nécessaire de la déclarer static au niveau
conceptuel.



Oui, sinon on risque de se poser des questions sur le pourquoi de ce
fonctionnement.

--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
Avatar
Michael Doubez
On 17 fév, 09:02, requinham wrote:
On 17 fév, 09:03, Mickaël Wolff wrote:

> requinham a écrit :

> > en fait est ce que c'est nécessaire de la déclarer static au nive au
> > conceptuel.

>    Oui, sinon on risque de se poser des questions sur le pourquoi d e ce
> fonctionnement.


A vrai dire, le fait de la déclarer static n'a pas de sens car pouvoir
fair un appel statique à destroy n'aura pas de sens tant qu'il n'y a
pas de singleton en memoire et dans le cas où il y en a on peut
l'appeler à partir du singleton exple : A::getInstance()->destroy()
sans problème vue que c'est la derniere instruction appelé dans la vi e
du singleton.



Ta question laisse supposer que tu vas appeler toi même la fonction de
destruction du singleton.

AMHA il vaut mieux un traitement générique de la durée de vie du
singleton C'est à dire qu'un singleton hérite d'une interface avec une
fonction membre virtual void destroy(); et qu'une fonction de netoyage
soit en charge de l'appeler au moment de la fin de vie.

Cette solution de permet de distinguer les types de singleton et leur
durée de vie associée à un évènement:
- détruit par le système (pas enregistré auprès d'un gestionnaire de
singleton)
- détruit explicitment à l'exit ou en sortie de scope
- détruit à la sortie d'un thread (pour les singletons TSS)
- détruit quand une dll est déchargée
- ...

Déjà, une fonction de destruction en sortie de programme ( avec
at_exit() ) devrait couvrir la plupart des cas courants et t'évitera
d'avoir à te creuser la tête pour svaoir quand appeler destroy().

Le mieux reste quand même de laisser le système réclamer les
ressources - si c'est possible.

--
Michael
Avatar
requinham
On 17 fév, 09:51, Michael Doubez wrote:
On 17 fév, 09:02, requinham wrote:



> On 17 fév, 09:03, Mickaël Wolff wrote:

> > requinham a écrit :

> > > en fait est ce que c'est nécessaire de la déclarer static au ni veau
> > > conceptuel.

> >    Oui, sinon on risque de se poser des questions sur le pourquoi de ce
> > fonctionnement.

> A vrai dire, le fait de la déclarer static n'a pas de sens car pouvoi r
> fair un appel statique à destroy n'aura pas de sens tant qu'il n'y a
> pas de singleton en memoire et dans le cas où il y en a on peut
> l'appeler à partir du singleton exple : A::getInstance()->destroy()
> sans problème vue que c'est la derniere instruction appelé dans la vie
> du singleton.

Ta question laisse supposer que tu vas appeler toi même la fonction de
destruction du singleton.

AMHA il vaut mieux un traitement générique de la durée de vie du
singleton C'est à dire qu'un singleton hérite d'une interface avec un e
fonction membre virtual void destroy(); et qu'une fonction de netoyage
soit en charge de l'appeler au moment de la fin de vie.

Cette solution de permet de distinguer les types de singleton et leur
durée de vie associée à un évènement:
  - détruit par le système (pas enregistré auprès d'un gestionn aire de
singleton)
  - détruit explicitment à l'exit ou en sortie de scope
  - détruit à la sortie d'un thread (pour les singletons TSS)
  - détruit quand une dll est déchargée
  - ...

Déjà, une fonction de destruction en sortie de programme ( avec
at_exit() ) devrait couvrir la plupart des cas courants et t'évitera
d'avoir à te creuser la tête pour svaoir quand appeler destroy().

Le mieux reste quand même de laisser le système réclamer les
ressources - si c'est possible.

--
Michael



bon si on a un cas dans lequel on devra détruire à la main le
singleton au milieu d'exécution du programme. Par exemple si on a un
GUI comportant plusieurs fonctionnalité parmi lesquelles une qui prend
un nom de fichier et appelle une dll pour le parser charger au fur et
à mesur ses données dans des structures spécifiques et mets ces
dernières à la disposition d'autres fonctionnalité. dans le cas ou je
veux changer le fichier je détruit le singleton (initialement créer
par le dll) et re-crée un autre pour le nouveau fichier.
Bon ça reste à titre d'exemple, mais la question est doit on déclarer
la fonction destroy() static ou non, conceptuellement parlant biensûr.

Merci
Avatar
James Kanze
On Feb 16, 11:41 am, requinham wrote:

je parlais avec un amis sur la declaration de la fonction qui
se chargera de la destruction de notre instance unique
destroy()



en fait est ce que c'est nécessaire de la déclarer static au
niveau conceptuel. car au niveau codage elle ne dérange pas
vue qu'elle sera la dernière à s'exécuter donc elle retournera
la main à un autre objet ou fonction différente de
l'instance ?



A votre avis comment ça se fait ?



Que normalement, on ne detruit pas un singleton. Le detruire
laisse la porte ouverte aux problèmes d'ordre de destruction.

Si on veut le detruire, il suffit que l'instance même soit
static, et le compilateur s'en occupera.

--
James Kanze
Avatar
Michael Doubez
On 17 fév, 20:28, requinham wrote:
On 17 fév, 09:51, Michael Doubez wrote:



> On 17 fév, 09:02, requinham wrote:

> > On 17 fév, 09:03, Mickaël Wolff wrote :

> > > requinham a écrit :

> > > > en fait est ce que c'est nécessaire de la déclarer static au niveau
> > > > conceptuel.

> > >    Oui, sinon on risque de se poser des questions sur le pourqu oi de ce
> > > fonctionnement.

> > A vrai dire, le fait de la déclarer static n'a pas de sens car pouv oir
> > fair un appel statique à destroy n'aura pas de sens tant qu'il n'y a
> > pas de singleton en memoire et dans le cas où il y en a on peut
> > l'appeler à partir du singleton exple : A::getInstance()->destroy()
> > sans problème vue que c'est la derniere instruction appelé dans l a vie
> > du singleton.

> Ta question laisse supposer que tu vas appeler toi même la fonction d e
> destruction du singleton.

> AMHA il vaut mieux un traitement générique de la durée de vie du
> singleton C'est à dire qu'un singleton hérite d'une interface avec une
> fonction membre virtual void destroy(); et qu'une fonction de netoyage
> soit en charge de l'appeler au moment de la fin de vie.

> Cette solution de permet de distinguer les types de singleton et leur
> durée de vie associée à un évènement:
>   - détruit par le système (pas enregistré auprès d'un gestio nnaire de
> singleton)
>   - détruit explicitment à l'exit ou en sortie de scope
>   - détruit à la sortie d'un thread (pour les singletons TSS)
>   - détruit quand une dll est déchargée
>   - ...

> Déjà, une fonction de destruction en sortie de programme ( avec
> at_exit() ) devrait couvrir la plupart des cas courants et t'évitera
> d'avoir à te creuser la tête pour svaoir quand appeler destroy().

> Le mieux reste quand même de laisser le système réclamer les
> ressources - si c'est possible.

> --
> Michael

bon si on a un cas dans lequel on devra détruire à la main le
singleton au milieu d'exécution du programme. Par exemple si on a un
GUI comportant plusieurs fonctionnalité parmi lesquelles une qui prend
un nom de fichier et appelle une dll pour le parser charger au fur et
à mesur ses données dans des structures spécifiques et mets ces
dernières à la disposition d'autres fonctionnalité. dans le cas ou je
veux changer le fichier je détruit le singleton (initialement créer
par le dll) et re-crée un autre pour le nouveau fichier.



Alors c'est un problème de design: il ne s'agit pas d'un singleton.

Bon ça reste à titre d'exemple, mais la question est doit on déclar er
la fonction destroy() static ou non, conceptuellement parlant biensûr.



AMA ça ne change pas grand chose.

--
Michael
Avatar
requinham
On 17 fév, 23:06, Michael Doubez wrote:
On 17 fév, 20:28, requinham wrote:



> On 17 fév, 09:51, Michael Doubez wrote:

> > On 17 fév, 09:02, requinham wrote:

> > > On 17 fév, 09:03, Mickaël Wolff wro te:

> > > > requinham a écrit :

> > > > > en fait est ce que c'est nécessaire de la déclarer static a u niveau
> > > > > conceptuel.

> > > >    Oui, sinon on risque de se poser des questions sur le pour quoi de ce
> > > > fonctionnement.

> > > A vrai dire, le fait de la déclarer static n'a pas de sens car po uvoir
> > > fair un appel statique à destroy n'aura pas de sens tant qu'il n' y a
> > > pas de singleton en memoire et dans le cas où il y en a on peut
> > > l'appeler à partir du singleton exple : A::getInstance()->destroy ()
> > > sans problème vue que c'est la derniere instruction appelé dans la vie
> > > du singleton.

> > Ta question laisse supposer que tu vas appeler toi même la fonction de
> > destruction du singleton.

> > AMHA il vaut mieux un traitement générique de la durée de vie d u
> > singleton C'est à dire qu'un singleton hérite d'une interface ave c une
> > fonction membre virtual void destroy(); et qu'une fonction de netoyag e
> > soit en charge de l'appeler au moment de la fin de vie.

> > Cette solution de permet de distinguer les types de singleton et leur
> > durée de vie associée à un évènement:
> >   - détruit par le système (pas enregistré auprès d'un gest ionnaire de
> > singleton)
> >   - détruit explicitment à l'exit ou en sortie de scope
> >   - détruit à la sortie d'un thread (pour les singletons TSS)
> >   - détruit quand une dll est déchargée
> >   - ...

> > Déjà, une fonction de destruction en sortie de programme ( avec
> > at_exit() ) devrait couvrir la plupart des cas courants et t'éviter a
> > d'avoir à te creuser la tête pour svaoir quand appeler destroy().

> > Le mieux reste quand même de laisser le système réclamer les
> > ressources - si c'est possible.

> > --
> > Michael

> bon si on a un cas dans lequel on devra détruire à la main le
> singleton au milieu d'exécution du programme. Par exemple si on a un
> GUI comportant plusieurs fonctionnalité parmi lesquelles une qui pren d
> un nom de fichier et appelle une dll pour le parser charger au fur et
> à mesur ses données dans des structures spécifiques et mets ces
> dernières à la disposition d'autres fonctionnalité. dans le cas o u je
> veux changer le fichier je détruit le singleton (initialement créer
> par le dll) et re-crée un autre pour le nouveau fichier.

Alors c'est un problème de design: il ne s'agit pas d'un singleton.

> Bon ça reste à titre d'exemple, mais la question est doit on décl arer
> la fonction destroy() static ou non, conceptuellement parlant biensûr .

AMA ça ne change pas grand chose.

--
Michael



et j'ai trouvé une réponse assez convaincante et qui montre que ça
change grand chose, meme plus c'est obligatoire dans le cas général :
(ce qui suit est la réponse d'un expert C++, je la copie ici) :
La raison est bien simple: si la fonction membre destroy n'était pas
statique, elle dépendrait... d'une instance de ton singleton.

Or, il est parfaitement possible que tu veuille utiliser (en créant au
besoin) ton instance de singleton "un peu partout" et que tu ne
veuille la détruire qu'à un seul endroit (typiquement, lors de
"l'extinction" finale), alors que... tu ne dispose pas forcément d'un
pointeur sur l'instance de ton singleton...

Du coup, si la fonction destroy n'était pas statique, tu en viendrait
à devoir écrire un code proche de

Code :
void finalize()
{
/*tout ce qu'il faut faire avant de détruire le singleton */
A::getInstance()->destroy();
/* tout ce qu'il faut faire après avoir détruit le singleton */
}

et tu admettra qu'il est pour le moins paradoxal de demander (et
éventuellement créer) l'instance du singleton pour... la détruire
directement

Ceci étant dit, l'invocation de delete sur NULL est garanti n'avoir
aucun effet...

Tu peux donc parfaitement éviter le test if (uniqueInstance != NULL)
dans la fonction destroy qui peut parfaitement prendre la forme de

Code:
static A::destroy()
{
delete uniqueInstance; // pas besoin de test
uniqueInstance = NULL; // tant pis si uniqueInstance vallait déjà
NULL
// maintenant, on en est sur :D
}

Enfin, on ne répète jamais assez le risque que l'on court à vouloir
tout transformer en singleton...

Dans bien des cas, il est tout à fait possible d'assurer l'unicité de
l'instance d'un type donné en veillant simplement à... interdire la
création de plus d'une instance.

Alors j'espère que c'est plus claire maintenant :)
Avatar
Fabien LE LEZ
On Thu, 18 Feb 2010 08:59:58 +0100, Mickaël Wolff
:

Ce qui me pose le plus de problème c'est delete *this, et qu'une
fonction membre est toujours en cours d'exécution alors que l'objet
auquel elle se réfère n'est plus valide.



Ce n'est pas bien méchant.
Une fonction membre, c'est équivalent à une fonction libre (et amie de
la classe) à qui on passe implicitement un pointeur appelé "this".
Le "delete *this" en lui-même ne pose pas de problème, puisque "this"
est valide pendant cet appel.
En revanche, après le retour de "delete *this", le pointeur "this"
n'est plus valide. Tu ne dois donc plus l'utiliser, explicitement ou
implicitement (en faisant référence à un membre de la classe). Mais à
part ça, tu peux faire tout ce qui te plaît.
Avatar
Mickaël Wolff
requinham a écrit :
A vrai dire, le fait de la déclarer static n'a pas de sens car pouvoir
fair un appel statique à destroy n'aura pas de sens tant qu'il n'y a
pas de singleton en memoire et dans le cas où il y en a on peut
l'appeler à partir du singleton exple : A::getInstance()->destroy()
sans problème vue que c'est la derniere instruction appelé dans la vie
du singleton.



Ce qui me pose le plus de problème c'est delete *this, et qu'une
fonction membre est toujours en cours d'exécution alors que l'objet
auquel elle se réfère n'est plus valide.

Mais finalement, ce qui manque, peut-etre, de pertinence, c'est
d'écrire une fonction membre inutile : delete singleton, qui utilise le
destructeur de la classe, est amplement suffisant. Je me demande donc
pourquoi tu veux une fonction membre destroy ?

--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
Avatar
Michael Doubez
On 17 fév, 23:57, requinham wrote:
On 17 fév, 23:06, Michael Doubez wrote:



> On 17 fév, 20:28, requinham wrote:

> > On 17 fév, 09:51, Michael Doubez wrote:

> > > On 17 fév, 09:02, requinham wrote:

> > > > On 17 fév, 09:03, Mickaël Wolff w rote:

> > > > > requinham a écrit :

> > > > > > en fait est ce que c'est nécessaire de la déclarer static au niveau
> > > > > > conceptuel.

> > > > >    Oui, sinon on risque de se poser des questions sur le po urquoi de ce
> > > > > fonctionnement.

> > > > A vrai dire, le fait de la déclarer static n'a pas de sens car pouvoir
> > > > fair un appel statique à destroy n'aura pas de sens tant qu'il n'y a
> > > > pas de singleton en memoire et dans le cas où il y en a on peut
> > > > l'appeler à partir du singleton exple : A::getInstance()->destr oy()
> > > > sans problème vue que c'est la derniere instruction appelé da ns la vie
> > > > du singleton.

> > > Ta question laisse supposer que tu vas appeler toi même la foncti on de
> > > destruction du singleton.

> > > AMHA il vaut mieux un traitement générique de la durée de vie du
> > > singleton C'est à dire qu'un singleton hérite d'une interface a vec une
> > > fonction membre virtual void destroy(); et qu'une fonction de netoy age
> > > soit en charge de l'appeler au moment de la fin de vie.

> > > Cette solution de permet de distinguer les types de singleton et le ur
> > > durée de vie associée à un évènement:
> > >   - détruit par le système (pas enregistré auprès d'un ge stionnaire de
> > > singleton)
> > >   - détruit explicitment à l'exit ou en sortie de scope
> > >   - détruit à la sortie d'un thread (pour les singletons TSS)
> > >   - détruit quand une dll est déchargée
> > >   - ...

> > > Déjà, une fonction de destruction en sortie de programme ( avec
> > > at_exit() ) devrait couvrir la plupart des cas courants et t'évit era
> > > d'avoir à te creuser la tête pour svaoir quand appeler destroy( ).

> > > Le mieux reste quand même de laisser le système réclamer les
> > > ressources - si c'est possible.

> > > --
> > > Michael

> > bon si on a un cas dans lequel on devra détruire à la main le
> > singleton au milieu d'exécution du programme. Par exemple si on a u n
> > GUI comportant plusieurs fonctionnalité parmi lesquelles une qui pr end
> > un nom de fichier et appelle une dll pour le parser charger au fur et
> > à mesur ses données dans des structures spécifiques et mets ces
> > dernières à la disposition d'autres fonctionnalité. dans le cas ou je
> > veux changer le fichier je détruit le singleton (initialement cré er
> > par le dll) et re-crée un autre pour le nouveau fichier.

> Alors c'est un problème de design: il ne s'agit pas d'un singleton.

> > Bon ça reste à titre d'exemple, mais la question est doit on dé clarer
> > la fonction destroy() static ou non, conceptuellement parlant biens ûr.

> AMA ça ne change pas grand chose.

et j'ai trouvé une réponse assez convaincante et qui montre que ça
change grand chose, meme plus c'est obligatoire dans le cas général :
(ce qui suit est la réponse d'un expert C++, je la copie ici) :
La raison est bien simple: si la fonction membre destroy n'était pas
statique, elle dépendrait... d'une instance de ton singleton.

Or, il est parfaitement possible que tu veuille utiliser (en créant au
besoin) ton instance de singleton "un peu partout" et que tu ne
veuille la détruire qu'à un seul endroit (typiquement, lors de
"l'extinction" finale), alors que... tu ne dispose pas forcément d'un
pointeur sur l'instance de ton singleton...

Du coup, si la fonction destroy n'était pas statique, tu en viendrait
à devoir écrire un code proche de

Code :
void finalize()
{
    /*tout ce qu'il faut faire avant de détruire le singleton */
    A::getInstance()->destroy();
    /* tout ce qu'il faut faire après avoir détruit le singleton */

}

et tu admettra qu'il est pour le moins paradoxal de demander (et
éventuellement créer) l'instance du singleton pour... la détruire
directement

Ceci étant dit, l'invocation de delete sur NULL est garanti n'avoir
aucun effet...

Tu peux donc parfaitement éviter le test if (uniqueInstance != NULL)
dans la fonction destroy qui peut parfaitement prendre la forme de

Code:
static A::destroy()
{
    delete uniqueInstance; // pas besoin de test
    uniqueInstance = NULL; // tant pis si uniqueInstance vallait d éjà
NULL
                           // maintenant, on en est sur :D

}

Enfin, on ne répète jamais assez le risque que l'on court à vouloir
tout transformer en singleton...

Dans bien des cas, il est tout à fait possible d'assurer l'unicité de
l'instance d'un type donné en veillant simplement à... interdire la
création de plus d'une instance.

Alors j'espère que c'est plus claire maintenant :)



Sauf que les prémices sont biaisés: si il s'agit d'un singleton qu'on
peut détruire alors il s'agit à priori d'un singleton qu'on peu
construire (un resettable singleton). Dans ce cas, la destruction
dépends de la création (ou d'une stratégie/d'un paramètre).

Ca ne fait pas sens de le détruire (delete) si le singleton est un
static, on veut juste que le singleton ne lui soit plus associé.

Par exemple, quelque chose comme:
main()
{
// le singleton que je veux utiliser dans mon programme
MySpecial app_singleton;
// le rendre accessible
Singleton::setInstance(&app_singleton);

{ // executer l'application
Application app;
app.run();
}

// ne plus utiliser le singleton
Singleton::setInstance(NULL);
}

C'est typiquement l'utilisation qui en est faite sous ACE pour
déterminer le type de Reactor de l'application.

--
Michael
1 2