Ricerca…


Osservazioni

Un Singleton è progettato per garantire che una classe abbia solo un'istanza e fornisca un accesso globale ad essa. Se si richiede solo un'istanza o un comodo punto di accesso globale, ma non entrambi, prendere in considerazione altre opzioni prima di passare al singleton.

Le variabili globali possono rendere più difficile ragionare sul codice. Ad esempio, se una delle funzioni di chiamata non è felice con i dati ricevuti da un Singleton, è necessario rintracciare ciò che inizialmente fornisce i dati non validi di Singleton.

I singleton incoraggiano anche l' accoppiamento , un termine usato per descrivere due componenti del codice che sono uniti, riducendo così ogni misura di autocontenimento di ogni componente.

I single non sono compatibili con la concorrenza. Quando una classe ha un punto di accesso globale, ogni thread ha la possibilità di accedervi che può portare a deadlock e condizioni di gara.

Infine, l'inizializzazione pigra può causare problemi di prestazioni se inizializzata nel momento sbagliato. La rimozione dell'inizializzazione pigra rimuove anche alcune delle caratteristiche che rendono Singleton interessante in primo luogo, come il polimorfismo (vedi Sottoclassi).

Fonti: Pattern di programmazione di gioco di Robert Nystrom

Inizializzazione pigra

Questo esempio è stato rimosso dalla sezione Q & A risposte qui: http://stackoverflow.com/a/1008289/3807729

Vedi questo articolo per un design semplice per un pigro valutato con distruzione garantita singleton:
Qualcuno può fornirmi un campione di Singleton in c ++?

Il classico pigro valutato e correttamente distrutto 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
};

Vedi questo articolo su quando usare un singleton: (non spesso)
Singleton: come dovrebbe essere usato

Vedi questo articolo sull'ordine di inizializzazione e su come far fronte:
Ordine di inizializzazione delle variabili statiche
Ricerca di problemi di ordine di inizializzazione statici C ++

Vedi questo articolo che descrive le vite:
Qual è la durata di una variabile statica in una funzione C ++?

Vedi questo articolo che discute alcune implicazioni di threading ai singleton:
Istanza Singleton dichiarata come variabile statica del metodo GetInstance

Vedi questo articolo che spiega perché il double check locking non funzionerà su C ++:
Quali sono tutti i comuni comportamenti indefiniti di cui un programmatore C ++ dovrebbe essere a conoscenza?

sottoclassi

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 questo esempio, un semplice switch del compilatore associa la classe API alla sottoclasse appropriata. In questo modo, è possibile accedere API senza essere accoppiati al codice specifico della piattaforma.

Singeton sicuro per thread

C ++ 11

Gli standard C ++ 11 garantiscono che l'inizializzazione degli oggetti dell'ambito della funzione sia inizializzata in modo sincronizzato. Questo può essere usato per implementare un singleton thread-safe con inizializzazione pigra .

class Foo
{
public:
    static Foo& instance()
    {
        static Foo inst;
        return inst;
    }        
private:
    Foo() {}
    Foo(const Foo&) = delete;
    Foo& operator =(const Foo&) = delete;
};

Deinitializzazione statica: sicuro singleton.

Ci sono volte con più oggetti statici in cui è necessario essere in grado di garantire che il singleton non verrà distrutto finché tutti gli oggetti statici che usano il singleton non ne hanno più bisogno.

In questo caso, std::shared_ptr può essere usato per mantenere vivo il singleton per tutti gli utenti anche quando i distruttori statici vengono chiamati alla fine del programma:

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() {}
};

NOTA: questo esempio viene visualizzato come risposta nella sezione Domande e risposte qui.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow