Historique de la question :
Le modèle Singleton a été proposé pour limiter la création d'une seule instance d'une classe donnée, ce qui était nécessaire pour mettre en œuvre des gestionnaires globaux (par exemple, des enregistreurs, des pools de ressources, des configureurs).
Problème :
La mise en œuvre du Singleton semble simple, mais en C++, des difficultés surgissent : la sécurité des threads, la destruction correcte, l'ordre d'initialisation.
Solution :
La manière la plus sûre et moderne de mettre en œuvre le Singleton utilise une variable locale statique à l'intérieur d'une fonction statique, garantissant une initialisation au premier accès, la sécurité des threads (à partir de C++11) et une destruction correcte.
Exemple de code :
class Singleton { public: static Singleton& instance() { static Singleton s; return s; } void doSomething() {} private: Singleton() {} Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; };
Caractéristiques clés :
Est-il possible de créer une deuxième instance du Singleton par sérialisation ou clonage ?
Oui. Si les méthodes de sérialisation/désérialisation sont implémentées ou si clone() est manuellement implémenté sans restreindre le constructeur de copie, une deuxième instance peut apparaître. Pour éviter cela, il est nécessaire d'interdire tous les moyens de copie, de clonage et de restauration par sérialisation.
Un Singleton sera-t-il correctement implémenté dans un environnement multithread en C++98/03 standard via une variable locale statique ?
Non. Les variables locales statiques avant C++11 ne garantissaient pas la sécurité des threads lors de l'initialisation. Cela pouvait entraîner la création de plusieurs instances si deux threads accédaient simultanément à la fonction instance(). En C++11 et ultérieur – le problème a été résolu au niveau de la norme.
Quand est détruite l'instance du Singleton créée via une variable locale statique ?
L'objet est détruit dans l'ordre inverse de sa création (LIFO) à la fin du programme (exit). Mais cela peut poser des problèmes si le destructeur accède à des objets déjà détruits.
Dans un système de journalisation, le développeur implémente un Singleton à l'aide d'un pointeur global et de new, oubliant d'interdire la copie. Le programme fonctionne, mais dans un environnement multithread, différents instances de l'enregistreur apparaissent parfois, et les messages sont perdus.
Avantages :
Inconvénients :
Le Singleton est implémenté via une variable locale statique dans une fonction statique, la copie est interdite. La sécurité des threads est assurée, le programme est évolutif, les journaux sont correctement divisés.
Avantages :
Inconvénients :