C++
Singleton ontwerppatroon
Zoeken…
Opmerkingen
Een Singleton is ontworpen om ervoor te zorgen dat een klasse slechts één instantie heeft en er een wereldwijd toegangspunt voor biedt. Als u slechts één exemplaar of een handig wereldwijd toegangspunt nodig hebt, maar niet beide, overweeg dan andere opties voordat u zich tot de singleton wendt.
Globale variabelen kunnen het moeilijker maken om over code te redeneren. Als een van de belfuncties bijvoorbeeld niet tevreden is met de gegevens die het van een Singleton ontvangt, moet u nu achterhalen wat de singleton in eerste instantie slechte gegevens geeft.
Singletons moedigen ook koppeling aan , een term die wordt gebruikt om twee componenten van code te beschrijven die met elkaar zijn verbonden, waardoor de eigen mate van zelfbeheersing van elke component wordt verminderd.
Singletons zijn niet samenvallend. Wanneer een klasse een wereldwijd toegangspunt heeft, heeft elke thread de mogelijkheid om er toegang toe te krijgen, wat kan leiden tot deadlocks en race-omstandigheden.
Ten slotte kan luie initialisatie prestatieproblemen veroorzaken als deze op het verkeerde moment wordt geïnitialiseerd. Door luie initialisatie te verwijderen, worden ook enkele functies verwijderd die Singleton in de eerste plaats interessant maken, zoals polymorfisme (zie Subklassen).
Bronnen: Game Programming Patterns door Robert Nystrom
Luie initialisatie
Dit voorbeeld is hier uit de Q & A
sectie gehaald: http://stackoverflow.com/a/1008289/3807729
Zie dit artikel voor een eenvoudig ontwerp voor een luie evaluatie met gegarandeerde vernietiging singleton:
Kan iemand mij een voorbeeld van Singleton in c ++ geven?
De klassieke luie geëvalueerde en correct vernietigde 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
};
Lees dit artikel over wanneer je een singleton moet gebruiken: (niet vaak)
Singleton: Hoe moet het worden gebruikt?
Zie dit twee artikel over initialisatie volgorde en hoe hiermee om te gaan:
Volgorde van initialisatie van statische variabelen
Problemen met C ++ statische initialisatie vinden
Zie dit artikel over levensduren:
Wat is de levensduur van een statische variabele in een C ++ -functie?
Zie dit artikel dat enkele threading-implicaties voor singletons bespreekt:
Singleton-instantie gedeclareerd als statische variabele van de GetInstance-methode
Zie dit artikel waarin wordt uitgelegd waarom dubbel gecontroleerde vergrendeling niet werkt op C ++:
Wat zijn alle veel voorkomende ongedefinieerde gedragingen die een C ++ programmeur zou moeten weten?
subklassen
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 dit voorbeeld bindt een eenvoudige compilerschakelaar de API
klasse aan de juiste subklasse. Op deze manier is API
toegankelijk zonder te zijn gekoppeld aan platformspecifieke code.
Draadveilige Singeton
De C ++ 11-normen garanderen dat de initialisatie van functiebereikobjecten op een gesynchroniseerde manier wordt geïnitialiseerd. Dit kan worden gebruikt om een thread-safe singleton met luie initialisatie te implementeren.
class Foo
{
public:
static Foo& instance()
{
static Foo inst;
return inst;
}
private:
Foo() {}
Foo(const Foo&) = delete;
Foo& operator =(const Foo&) = delete;
};
Statische deinitialisatie-veilige singleton.
Er zijn tijden met meerdere statische objecten waarbij je moet kunnen garanderen dat de singleton niet zal worden vernietigd totdat alle statische objecten die de singleton gebruiken deze niet langer nodig hebben.
In dit geval kan std::shared_ptr
worden gebruikt om de singleton in leven te houden voor alle gebruikers, zelfs wanneer de statische destructors aan het einde van het programma worden aangeroepen:
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() {}
};
OPMERKING: Dit voorbeeld verschijnt als antwoord in het gedeelte Vragen en antwoorden hier.