Storia della domanda:
Il pattern Singleton è stato proposto per limitare la creazione di una sola istanza di una determinata classe, richiesta per implementare gestori globali (ad esempio, logger, pool di risorse, configuratori).
Problema:
L'implementazione del Singleton sembra semplice, ma in C++ sorgono difficoltà: sicurezza nei thread, correttezza della distruzione, ordine di inizializzazione.
Soluzione:
Il modo più sicuro e moderno per implementare Singleton utilizza una variabile locale statica all'interno di una funzione statica, garantendo l'inizializzazione al primo accesso, la sicurezza nei thread (a partire da C++11) e la corretta distruzione.
Esempio di codice:
class Singleton { public: static Singleton& instance() { static Singleton s; return s; } void doSomething() {} private: Singleton() {} Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; };
Caratteristiche chiave:
È possibile creare un secondo istanza di Singleton tramite serializzazione o clonazione?
Sì. Se vengono implementati metodi di serializzazione/deserializzazione o si implementa manualmente clone(), senza limitare il costruttore di copia, potrebbe apparire un secondo istanza. Per evitare ciò, è necessario vietare tutti i modi di copia, clonazione e recupero tramite serializzazione.
Sarà correttamente implementato Singleton in un ambiente multithreading nel C++98/03 secondo lo standard tramite una variabile locale statica?
No. Le variabili locali statiche prima del C++11 non garantivano la sicurezza nei thread durante l'inizializzazione. Questo poteva portare a creare più istanze se due thread accedevano simultaneamente alla funzione instance(). In C++11 e versioni successive, il problema è stato risolto a livello di standard.
Quando viene distrutta l'istanza Singleton creata tramite una variabile locale statica?
L'oggetto viene distrutto in ordine inverso rispetto alla creazione (LIFO) durante la fase di terminazione del programma (exit). Ma questo può portare a problemi se nel distruttore si accede ad oggetti già distrutti.
Nel sistema di logging, lo sviluppatore implementa Singleton tramite un puntatore globale e new, dimenticando di vietare la copia. Il programma funziona, ma in un ambiente multithreading si ottengono talvolta istanze diverse del logger, i messaggi vengono persi.
Vantaggi:
Svantaggi:
Il Singleton è implementato tramite una variabile locale statica in una funzione statica, ed è vietata la copia. La sicurezza nei thread è garantita, il programma si scala, i log sono correttamente separati.
Vantaggi:
Svantaggi: