C++
Singleton Design Pattern
Suche…
Bemerkungen
Ein Singleton soll sicherstellen, dass eine Klasse nur eine Instanz hat und einen globalen Zugriffspunkt bietet. Wenn Sie nur eine Instanz oder einen geeigneten globalen Zugriffspunkt benötigen, jedoch nicht beide, sollten Sie andere Optionen in Betracht ziehen, bevor Sie sich dem Einzelspieler zuwenden.
Globale Variablen können es schwieriger machen, über Code nachzudenken. Wenn zum Beispiel eine der aufrufenden Funktionen mit den Daten, die sie von einem Singleton empfängt, nicht zufrieden ist, müssen Sie jetzt herausfinden, was zuerst die fehlerhaften Daten des Singleton an erster Stelle gibt.
Singletons fördern auch die Kopplung , ein Begriff, der verwendet wird, um zwei Komponenten des Codes zu beschreiben, die miteinander verbunden sind, wodurch die eigenen Maßnahmen zur Selbsteinschließung jeder Komponente reduziert werden.
Singletons sind nicht gleichlaufsicher. Wenn eine Klasse über einen globalen Zugriffspunkt verfügt, kann jeder Thread darauf zugreifen, was zu Deadlocks und Race-Bedingungen führen kann.
Schließlich kann eine langsame Initialisierung zu Leistungsproblemen führen, wenn sie zum falschen Zeitpunkt initialisiert wird. Durch das Entfernen der verzögerten Initialisierung werden auch einige der Features entfernt, die Singletons erst recht interessant machen, wie etwa Polymorphismus (siehe Unterklassen).
Quellen: Spielprogrammierungsmuster von Robert Nystrom
Faule Initialisierung
Dieses Beispiel wurde aus dem Q & A
Abschnitt hier entfernt: http://stackoverflow.com/a/1008289/3807729
In diesem Artikel finden Sie ein einfaches Design für ein Lazy, das mit garantierter Zerstörung bewertet wird:
Kann mir jemand eine Probe von Singleton in c ++ zur Verfügung stellen?
Der klassische Lazy hat Singleton ausgewertet und richtig zerstört.
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
};
In diesem Artikel wird beschrieben, wann ein Singleton verwendet wird: (nicht oft)
Singleton: Wie soll es verwendet werden?
In diesen beiden Artikeln finden Sie Informationen zur Initialisierungsreihenfolge und zum Umgang damit:
Reihenfolge der Initialisierung der statischen Variablen
Probleme mit der statischen C ++ - Initialisierungsreihenfolge finden
In diesem Artikel wird die Lebensdauer beschrieben:
Wie lang ist eine statische Variable in einer C ++ - Funktion?
In diesem Artikel werden einige Threading-Implikationen für Singletons beschrieben:
Singleton-Instanz, die als statische Variable der GetInstance-Methode deklariert ist
In diesem Artikel wird erläutert, warum doppelt gesichertes Sperren in C ++ nicht funktioniert:
Was sind die allgemeinen undefinierten Verhaltensweisen, über die ein C ++ - Programmierer Bescheid wissen sollte?
Unterklassen
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;
}
In diesem Beispiel bindet ein einfacher Compiler-Switch die API
Klasse an die entsprechende Unterklasse. Auf diese Weise kann auf die API
zugegriffen werden, ohne an plattformspezifischen Code gekoppelt zu sein.
Fadensicheres Singeton
Die C ++ 11-Standards garantieren, dass die Initialisierung von Funktionsumfangsobjekten synchronisiert initialisiert wird. Dies kann verwendet werden, um einen Thread-sicheren Singleton mit verzögerter Initialisierung zu implementieren.
class Foo
{
public:
static Foo& instance()
{
static Foo inst;
return inst;
}
private:
Foo() {}
Foo(const Foo&) = delete;
Foo& operator =(const Foo&) = delete;
};
Statischer Deinitialisierungssicherer Singleton.
Es gibt Zeiten mit mehreren statischen Objekten, bei denen Sie sicherstellen müssen, dass der Singleton nicht zerstört wird, bis alle statischen Objekte, die den Singleton verwenden, ihn nicht mehr benötigen.
In diesem Fall kann std::shared_ptr
verwendet werden, um den Singleton für alle Benutzer am Leben zu erhalten, selbst wenn die statischen Destruktoren am Ende des Programms aufgerufen werden:
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() {}
};
HINWEIS: Dieses Beispiel wird hier als Antwort im Abschnitt "Fragen und Antworten" angezeigt.