Newsgroup: it.comp.lang.c++
Titolo: Static Singleton

Ciao a tutti.
Chiedo il vostro aiuto per discutere di un piccolo pattern a cui sto
pensando da un po' di tempo e che vorrei utilizzare in un progetto che sto
portando avanti. L'ho battezzato provvisoriamente "Static Singleton", anche
se non sono sicuro se il nome si possa ritenere corretto.
Spiego brevemente di cosa si tratta: l'idea "standard" di singleton e'
qualcosa fatto piu' o meno cosi':
-----------------------------------------------------
class Singleton
  {
  public:
    static Singleton& getInstance()
      {
      if ( instance == 0 ) instance = new Singleton;
      return *instance;
  private:
    static Singleton * instance;
  };
-----------------------------------------------------
Il vantaggio di una implementazione di questo tipo rispetto all'uso di
una "Singleton instance" statica e' ovviamente che se getInstance() non
viene mai invocata, si evita di inizializzare il singleton inutilmente.
Nel mio progetto avrei necessita' di evitare questa lazy-optimization,
inizializzando l'oggetto il prima possibile, garantendo pero' nel contempo
che se nessun oggetto fa uso del singleton, allora questo non viene
inizializzato.
L'idea sarebbe quella di incapsularne un'istanza statica in una classe
template, cosi' che il compilatore la istanzi soltanto quando il template
viene istanziato:
-------------------------------------------------------------------------
template <typename dummy>
class StaticSingletonTempl;
class StaticSingletonImpl        // Il Singleton vero e proprio
  {
  private:
    StaticSingletonImpl() 
      { std::cout << __PRETTY_FUNCTION__ << std::endl; }
    void foo() 
      { std::cout << __PRETTY_FUNCTION__ << std::endl; }
  template <typename T>
  friend class StaticSingletonTempl;
  };
template <typename dummy = void>
class StaticSingletonTempl       // Wrapper utilizzabile nel codice
  {
  public:
    StaticSingletonTempl()
    {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
    S.foo();
    }
  private:
    static StaticSingletonImpl S;
  };
template <typename dummy>
StaticSingletonImpl StaticSingletonTempl<dummy>::S;
typedef StaticSingletonTempl<> StaticSingleton;     // Utile...
----------------------------------------------------------------------
Cosi' facendo, ottengo che solo dichiarando (almeno) una variabile di tipo
StaticSingleton viene invocato il costruttore di StaticSingletonImpl.
In altre parole, l'output di questo programma:
------------------------------------------------
int main()
  {
  std::cout << __PRETTY_FUNCTION__ << std::endl;
  StaticSingleton s;  //(*)
  return 0;
  }
------------------------------------------------
e' pari a:
----------------------------------------------------------------------
StaticSingletonImpl::StaticSingletonImpl()
int main()
StaticSingletonTempl<dummy>::StaticSingletonTempl() [with dummy = int]
void StaticSingletonImpl::foo()
----------------------------------------------------------------------
e si riduce al solo "int main()" se commento la linea (*).
Mi piacerebbe discutere delle potenzialita' e dei limiti di questa tecnica,
e magari trovare modo di migliorarla un po'. Uno dei problemi che ho notato
si ha indicando oggetti di tipo StaticSingleton fuori dal main, infatti
l'ordine di inizializzazione non e' piu' garantito, e diventa:
-----------------------------------------------------------------------
StaticSingletonTempl<dummy>::StaticSingletonTempl() [with dummy = void]
void StaticSingletonImpl::foo()
StaticSingletonImpl::StaticSingletonImpl()
int main()
-----------------------------------------------------------------------
Che non va bene!
Saluti a tutti,
Frank.

 non e' piu' garantito
Il dramma del C++... devi scegliere. Se inizializzi al primo utilizzo, sei 
certo che l'ordine di inizializzazione sia corretto, ma non inizializzi 
l'oggetto il prima possibile. Se invece scegli di inizializzarlo con 
inizializzatori statici, t'affidi al fato riguardo l'ordine di 
inizializzazione nei confronti degli altri inizializzatori statici.
Per non reinventare la ruota, in giro c'e' uno scheletro di singleton con 
policy di "vita" che potrebbe essere interessante (se non ricordo male 
dovrebbe essere di Alexandrescu).
--*PaN!* 

 dovrebbe essere di Alexandrescu).
Uhm, si. Ho presente il suo libro (il capitolo 6 descrive proprio questo),
ma le soluzioni proposte non sono sufficienti. Resta sempre il problema di
dover decidere tra inizializzazione on-the-fly e garanzia sull'ordine di
inizializzazione. Penso che la soluzione migliore possa essere utilizzare
una classe template come ho fatto io per garantire che comunque il
Singleton venga inizializzato per lo meno prima del main(), ma lasciare al
suo interno un meccanismo di inizializzazione "al primo utilizzo" per non
incorrere in problemi di inizializzazione degli oggetti statici.
Mi chiedevo se si riusciva a fare qualcosa di meglio...

 piu' banale.
Ma non e' possibile... se esistesse una tecnica che mi permette di 
inizializzare una variabile "per prima" e io l'applicassi a due oggetti, 
quale dei due verrebbe inizializzato per primo?
L'unica cosa possibile sarebbe dichiarare esplicitamente le dipendenze tra 
oggetti con inizializzatori statici...
--
Marco