C++
Singleton Design Pattern
Recherche…
Remarques
Un Singleton est conçu pour garantir qu'une classe ne possède qu'une seule instance et fournit un point d'accès global à celle-ci. Si vous ne souhaitez qu'une seule instance ou un point d'accès global pratique, mais pas les deux, envisagez d'autres options avant de passer au singleton.
Les variables globales peuvent rendre la raison du code plus difficile. Par exemple, si l'une des fonctions appelantes n'est pas satisfaite des données qu'elle reçoit d'un Singleton, vous devez maintenant rechercher en premier lieu ce qui donne en premier lieu les données singleton incorrectes.
Les singletons encouragent également le couplage , un terme utilisé pour décrire deux composants du code qui sont réunis, réduisant ainsi la propre mesure d'auto-confinement de chaque composant.
Les singletons ne sont pas compatibles avec la concurrence. Lorsqu'une classe dispose d'un point d'accès global, chaque thread a la possibilité d'y accéder, ce qui peut entraîner des blocages et des conditions de course.
Enfin, l'initialisation différée peut entraîner des problèmes de performances si elle est initialisée au mauvais moment. La suppression de l'initialisation différée supprime également certaines des fonctionnalités qui rendent Singleton intéressant en premier lieu, comme le polymorphisme (voir Sous-classes).
Sources: Patterns de programmation de jeux par Robert Nystrom
Initialisation paresseuse
Cet exemple a été retiré de la section Q & A
ici: http://stackoverflow.com/a/1008289/3807729
Voir cet article pour un design simple pour un singleton paresseux évalué avec destruction garantie:
Quelqu'un peut-il me fournir un échantillon de Singleton en c ++?
Le classique paresseux a évalué et correctement détruit le singleton.
class S
{
public:
static S& getInstance()
{
static S instance; // Guaranteed to be destroyed.
// Instantiated on first use.
return instance;
}
private:
S() {}; // Constructor? (the {} brackets) are needed here.
// C++ 03
// ========
// Dont forget to declare these two. You want to make sure they
// are unacceptable otherwise you may accidentally get copies of
// your singleton appearing.
S(S const&); // Don't Implement
void operator=(S const&); // Don't implement
// C++ 11
// =======
// We can use the better technique of deleting the methods
// we don't want.
public:
S(S const&) = delete;
void operator=(S const&) = delete;
// Note: Scott Meyers mentions in his Effective Modern
// C++ book, that deleted functions should generally
// be public as it results in better error messages
// due to the compilers behavior to check accessibility
// before deleted status
};
Voir cet article sur quand utiliser un singleton: (pas souvent)
Singleton: Comment devrait-il être utilisé
Voir cet article sur l'ordre d'initialisation et comment faire face:
Ordre d'initialisation des variables statiques
Recherche des problèmes d'ordre d'initialisation statiques C ++
Voir cet article décrivant des vies:
Quelle est la durée de vie d'une variable statique dans une fonction C ++?
Voir cet article qui traite de certaines implications pour les singletons:
Instance Singleton déclarée comme variable statique de la méthode GetInstance
Voir cet article qui explique pourquoi le verrouillage à double vérification ne fonctionnera pas sous C ++:
Quels sont les comportements non définis courants qu'un programmeur C ++ doit connaître?
Des sous-classes
class API
{
public:
static API& instance();
virtual ~API() {}
virtual const char* func1() = 0;
virtual void func2() = 0;
protected:
API() {}
API(const API&) = delete;
API& operator=(const API&) = delete;
};
class WindowsAPI : public API
{
public:
virtual const char* func1() override { /* Windows code */ }
virtual void func2() override { /* Windows code */ }
};
class LinuxAPI : public API
{
public:
virtual const char* func1() override { /* Linux code */ }
virtual void func2() override { /* Linux code */ }
};
API& API::instance() {
#if PLATFORM == WIN32
static WindowsAPI instance;
#elif PLATFORM = LINUX
static LinuxAPI instance;
#endif
return instance;
}
Dans cet exemple, un simple commutateur de compilateur lie la classe API
à la sous-classe appropriée. De cette manière, l’ API
est accessible sans être couplée à un code spécifique à la plate-forme.
Filet Singeton
Les normes C ++ 11 garantissent que l'initialisation des objets de portée de fonction est initialisée de manière synchronisée. Cela peut être utilisé pour implémenter un singleton thread-safe avec initialisation différée .
class Foo
{
public:
static Foo& instance()
{
static Foo inst;
return inst;
}
private:
Foo() {}
Foo(const Foo&) = delete;
Foo& operator =(const Foo&) = delete;
};
Singleton de désinitialisation statique.
Il y a des fois avec plusieurs objets statiques où vous devez pouvoir garantir que le singleton ne sera pas détruit tant que tous les objets statiques utilisant le singleton n'en auront plus besoin.
Dans ce cas, std::shared_ptr
peut être utilisé pour maintenir le singleton en vie pour tous les utilisateurs, même lorsque les destructeurs statiques sont appelés à la fin du programme:
class Singleton
{
public:
Singleton(Singleton const&) = delete;
Singleton& operator=(Singleton const&) = delete;
static std::shared_ptr<Singleton> instance()
{
static std::shared_ptr<Singleton> s{new Singleton};
return s;
}
private:
Singleton() {}
};
REMARQUE: Cet exemple apparaît comme une réponse dans la section Q & R ici.