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

Autour d'un singleton

14 réponses
Avatar
Programmer
J'ai utilisé le design pattern Singleton dans un développement. J'ai
donc implémenté une méthode (c'est juste du pseudo code, ne cherchez
pas les erreurs de C++) :

MonSingleton *MonSingleton::GetInstance()
{
if (instance == NULL)
instance = new MonSingleton();
return instance;
}

et dans le destructeur de ma classe je fait :

MonSingleton *MonSingleton::~MonSingleton()
{
delete instance;
}


Toutefois, je ne comprend pas bien à quel moment s'effectue la
destruction de l'instance, puisque je n'appelle jamais delete sur
l'objet de type MonSingleton, que je ne le manipule qu'à travers la
méthode statique GetInstance() (exemple :
MonSingleton::GetInstance()->MaFonction()).

J'avais pensé à une méthode statique ClearInstance() qui se chargerait
de faire le delete, mais cela m'étonne tout de même de devoir supprimer
l'instance explicitement en appelant cette méthode.

Pouvez vous me conseiller ?

10 réponses

1 2
Avatar
Alain Ketterlin
Programmer writes:

J'ai utilisé le design pattern Singleton dans un développement. J'ai
donc implémenté une méthode (c'est juste du pseudo code, n e cherchez
pas les erreurs de C++) :

MonSingleton *MonSingleton::GetInstance()
{
if (instance == NULL)
instance = new MonSingleton();
return instance;
}



En fait c'est inutile. Si tu regardes la definition de "instance", tu
verras qu'on peut très bien se débrouiller pour que l'instance ex iste
toujours. En pseudo C++

class MonSingleton {
static MonSingleton instance;
...
};
MonSingleton MonSingleton::instance;

(il serait étonnant que le constructeur prenne des paramètres, ma is
c'est possible.) Bien sûr, le champ pourrait être const et public , ou
private et accédé via un pointeur ou une référence renv oyée par une
fonction static.

et dans le destructeur de ma classe je fait :

MonSingleton *MonSingleton::~MonSingleton()
{
delete instance;
}

Toutefois, je ne comprend pas bien à quel moment s'effectue la
destruction de l'instance, puisque je n'appelle jamais delete sur
l'objet de type MonSingleton,



Tu te trompes : le destructeur, c'est pour la destruction des instances,
pas pour faire le ménage au niveau de la classe. Dans le fragment
ci-dessus, il n'y a rien à faire pour detruire l'instance, elle sera
détruite implicitement.

que je ne le manipule qu'à travers la méthode statique GetInsta nce()
(exemple : MonSingleton::GetInstance()->MaFonction()).



Qui pourrait même être MonSingleton::instance.MaFonction()

J'avais pensé à une méthode statique ClearInstance() qui s e chargerait
de faire le delete, mais cela m'étonne tout de même de devoir
supprimer l'instance explicitement en appelant cette méthode.



Oui, tu as raison, ce n'est pas nécessaire. L'instance est construite
avant le début du main, et détruite après la fin du main (y compris si
tu quittes le programme par exit()).

-- Alain.
Avatar
Fabien LE LEZ
On Tue, 02 Nov 2010 17:43:19 +0100, Programmer :

Toutefois, je ne comprend pas bien à quel moment s'effectue la
destruction de l'instance



Généralement, jamais. Le principe d'un singleton, c'est d'exister
pendant toute la durée du programme.

Du coup, le détruire n'a pas forcément d'intérêt, et bien souvent
n'est même pas possible. Assure-toi que son destructeur ne fait rien
d'intéressant, et laisse l'OS libérer la mémoire quand le programme se
termine.
Avatar
Fabien LE LEZ
On Tue, 02 Nov 2010 18:43:52 +0100, Alain Ketterlin
:

tu
verras qu'on peut très bien se débrouiller pour que l'instance existe
toujours.



Note qu'en général, on ne veut créer l'objet que si, et quand, on en a
besoin. Dans ce cas, on peut faire un truc comme ça :

class MonSingleton
{
public:
static MonSingleton& Get();
private:
MonSingleton();
};

MonSingleton& MonSingleton::Get()
{
static MonSingleton m;
return m;
}
Avatar
Fabien LE LEZ
On Tue, 02 Nov 2010 17:43:19 +0100, Programmer :

Toutefois, je ne comprend pas bien à quel moment s'effectue la
destruction de l'instance



Une fois que la fonction main() se termine, il se passe les choses
suivantes :

1/ Les variables statiques sont détruites, dans un ordre pas
entièrement prévisible. Leur destructeur est appelé.
2/ L'exécution prend fin, et le système libère toutes les ressources
encore utilisées (mémoire, fichiers ouverts, sockets, etc.)

Si tu utilises une variable statique (cf le message d'Alain ou ma
réponse à ce message), le destructeur sera appelé. Si tu utilises une
variable allouée par new (ta version), il ne sera pas appelé.

As-tu besoin que le destructeur soit appelé ?
Est-ce qu'il fait quelque chose ?
Si oui, quoi ?

Imagine que tu as deux singletons, et que le destructeur du premier
appelle une fonction du deuxième. Il faut alors t'assurer que le
deuxième existe toujours, i.e. que le deuxième singleton soit détruit
après le premier. Ce n'est pas trivial ; la solution la plus simple
est de ne jamais détruire le deuxième. Ainsi, le premier pourra être
une variable statique (et donc, son destructeur sera appelé, ce qui
est important car il fait quelque chose), alors que le deuxième sera
alloué par new, et jamais désalloué.
Avatar
jeanpul
On 2 nov, 17:43, Programmer wrote:
J'ai utilisé le design pattern Singleton dans un développement. J'ai
donc implémenté une méthode (c'est juste du pseudo code, ne cherche z
pas les erreurs de C++) :

MonSingleton *MonSingleton::GetInstance()
{
if (instance == NULL)
   instance = new MonSingleton();
return instance;

}

et dans le destructeur de ma classe je fait :

MonSingleton *MonSingleton::~MonSingleton()
{
delete instance;

}

Toutefois, je ne comprend pas bien à quel moment s'effectue la
destruction de l'instance, puisque je n'appelle jamais delete sur
l'objet de type MonSingleton, que je ne le manipule qu'à travers la
méthode statique GetInstance() (exemple :
MonSingleton::GetInstance()->MaFonction()).

J'avais pensé à une méthode statique ClearInstance() qui se charger ait
de faire le delete, mais cela m'étonne tout de même de devoir supprim er
l'instance explicitement en appelant cette méthode.

Pouvez vous me conseiller ?



Je vous conseille, tout d'abord, d'aller lire (http://blogs.msdn.com/b/
scottdensmore/archive/2004/05/25/140827.aspx par exemple) les
arguments pour et contre l'utilisation des singleton. Sinon, une
déclaration "statique" de l'instance me paraît la plus adaptée pour
garantir sa durée de vie pendant toute l'exécution du programme.

Cordialement,

Fabien
Avatar
James Kanze
On Nov 10, 8:37 am, jeanpul wrote:
On 2 nov, 17:43, Programmer wrote:
> J'ai utilisé le design pattern Singleton dans un développement. J'a i
> donc implémenté une méthode (c'est juste du pseudo code, ne cherc hez
> pas les erreurs de C++) :

> MonSingleton *MonSingleton::GetInstance()
> {
> if (instance == NULL)
> instance = new MonSingleton();
> return instance;
> }

> et dans le destructeur de ma classe je fait :

> MonSingleton *MonSingleton::~MonSingleton()
> {
> delete instance;
> }

> Toutefois, je ne comprend pas bien à quel moment s'effectue la
> destruction de l'instance, puisque je n'appelle jamais delete sur
> l'objet de type MonSingleton, que je ne le manipule qu'à travers la
> méthode statique GetInstance() (exemple :
> MonSingleton::GetInstance()->MaFonction()).

> J'avais pensé à une méthode statique ClearInstance() qui se charg erait
> de faire le delete, mais cela m'étonne tout de même de devoir suppr imer
> l'instance explicitement en appelant cette méthode.

> Pouvez vous me conseiller ?

Je vous conseille, tout d'abord, d'aller lire
(http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx
par exemple) les arguments pour et contre l'utilisation des
singleton.



Pas une référence particulièrement intéressante, étant donné qu e
l'auteur donne l'air de ne pas comprendre la motivation derrière
le modèle de conception. (Mais évidemment, beaucoup de
programmateurs C++ s'en servent pour résoudre des questions de
l'ordre d'initialisation, plutôt que pour limiter le nombre
d'instances à un.)

Sinon, une déclaration "statique" de l'instance me paraît la
plus adaptée pour garantir sa durée de vie pendant toute
l'exécution du programme.



Une déclaration statique ne résoud pas les problèmes de l'order
d'initialisation, ni de l'ordre de destruction.

--
James Kanze
Avatar
Michael Doubez
On 3 nov, 04:21, Fabien LE LEZ wrote:
On Tue, 02 Nov 2010 17:43:19 +0100, Programmer :

>Toutefois, je ne comprend pas bien quel moment s'effectue la
>destruction de l'instance

G n ralement, jamais. Le principe d'un singleton, c'est d'exister
pendant toute la dur e du programme.



Non, le principe du singleton est d'assurer qu'il existe au plus une
instance d'une classe à un moment donné. Un singleton peut être
construit ou détruit à d'autre moment dans le programme (par exemple
quand le singleton est issu d'un load dynamique de dll).

Ce que que tu définis est une globale. Comme le dit James Kanze, en C+
+, le même idiome est utilisé pour faire un singleton et contrôler le s
dépendance entre globales avant d'entrer dans le main() donc ça prête
à confusion.

(Remarque: la confusion existe dans d'autres langages)

--
Michael
Avatar
az
On Wed, 03 Nov 2010 04:21:27 +0100, Fabien LE LEZ wrote:

et laisse l'OS libérer la mémoire quand le programme se
termine.



Laisser des fuites de mémoire, c'est programmer comme un porc, dit-on.
Avatar
Fabien LE LEZ
On Thu, 11 Nov 2010 20:28:40 +0000 (UTC), az :

et laisse l'OS libérer la mémoire quand le programme se
termine.



Laisser des fuites de mémoire, c'est programmer comme un porc, dit-on.



Oui.

Une fuite mémoire, c'est quand le programme utilise de plus en plus de
mémoire au fur et à mesure de son exécution. C'est généralement
mauvais si le programme est conçu pour tourner longtemps.

En revanche, si une zone mémoire (de taille fixe) est nécessaire au
programme jusqu'à la fin de son exécution, cette zone ne doit être
libérée qu'à la fin de l'exécution. Qu'elle soit libérée explicitement
(via delete ou free()) ou bien automatiquement par le système, ne
change rien.
Et tant que la taille de cette zone reste fixe, elle ne peut pas être
considérée comme une fuite mémoire.
Avatar
az
On Thu, 11 Nov 2010 21:54:52 +0100, Fabien LE LEZ wrote:

On Thu, 11 Nov 2010 20:28:40 +0000 (UTC), az :

et laisse l'OS libérer la mémoire quand le programme se termine.



Laisser des fuites de mémoire, c'est programmer comme un porc, dit-on.



Oui.

Une fuite mémoire, c'est quand le programme utilise de plus en plus de
mémoire au fur et à mesure de son exécution. C'est généralement mauvais
si le programme est conçu pour tourner longtemps.

En revanche, si une zone mémoire (de taille fixe) est nécessaire au
programme jusqu'à la fin de son exécution, cette zone ne doit être
libérée qu'à la fin de l'exécution. Qu'elle soit libérée explicitement
(via delete ou free()) ou bien automatiquement par le système, ne change
rien.
Et tant que la taille de cette zone reste fixe, elle ne peut pas être
considérée comme une fuite mémoire.



Votre raisonnement est tout à fait correct. Seulement le singleton n'est
pas fait pour être necessaire tout au long de l'exécution du programme
(comme l'a fait remarquer Michael Doubez).
Une façon de faire est d'implémenter deux méthodes statiques register()
et release(). La première incrémente un compteur (et appelle
implicitement getInstance()), la deuxième le décrémente un par un jusqu'à
0 puis détruit l'instance. Tout objet qui a besoin d'acceder au singleton
appelle register() dans son constructeur (et peux garder une référence
vers l'instance à ce moment là) et release() dans son destructeur (on
émule le comportement d'un gc préhistorique dans notre singleton). Chaque
implémentation répond à un besoin conceptuel précis, il est donc dangereux
de banaliser le singleton à un tiroir à instance qui baignent là jusqu'à
la fin du programme.
1 2