Newsgroup: it.comp.lang.c++
Titolo: Ordine di inizializzazione delle statiche

Mentre pensavo al problema di gestire l'ordine di inizializzazione
delle variabili statiche definite in moduli diversi mi è venuta in
mente una possibile soluzione. E' un po' arzigogolata e richiede un
certo impegno da parte di chi scrive il codice, ma ha il pregio di
essere portabile (almeno credo).
Il concetto di fondo è semplice; prendiamo come esempio le variabili
globali, ma (credo) che il discorso si possa estendere anche agli
altri tipi di statiche. Invece di definire direttamente una variabile,
definiamo un oggetto che implementa un metodo Get(): tale metodo sarà
quello che poi restituirà l'oggetto, qualcosa come
XXX& yyy::Get() {
	static XXX s;
	return s;
}
Ovviamente per fare ciò nel metodo più generico possibile useremo un
template; e qui iniziano i problemi: se l'unico parametro del template
fosse solo il tipo della classe che ci serve incontreremo dei problemi
nel momento in cui dobbiamo definire due variabili globali diverse ma
dello stesso tipo, in quanto l'istanza all'interno di Get() verrebbe
creata una sola volta (ok, la chiarezza non è il mio forte :-)
Per risolvere ho pensato di passare al template un argomento fittizzio
(ad esempio un int), in modo tale da poterlo utilizzare per avere più
versioni di Get() (e quindi più istanze della variabile). Forse con il
codice si capisce meglio:
// File Static.h
template<class T,int>
class Static {
  Static(const Static&); // impedisco copia e assegnamento
  Static& operator=(const Static&);
public:
  Static() { }
  T& Get() {
    static T s; /* la variabile verrà creata alla prima chiamata di
                          Get(). Abbiamo il controllo su quando ciò
                          avverrà */
    return s;
  }
};
Dopo questo bisogna stare un po' attenti. Al posto di:
	static ABC abc1;
	static ABC abc2;
dovremmo scrivere:
	Static<ABC,1> abc1;
	Static<ABC,2> abc2;
stando attenti a non usare due volte lo stesso numero, altrimenti
avremmo due "pseudo-riferimenti" alla stessa istanza.
Una volta arrivati fino qua il gioco è quasi fatto: per controllare
*esattamente* l'ordine di inizializzazione possiamo sfruttare il fatto
che le inizializzazioni all'interno della stessa unità di compilazione
avvengo nell'ordine in cui sono scritte. Perciò:
// file Static_init.cpp
extern Static<ABC,1> abc1;
extern Static<ABC,2> abc2;
ABC& prima_statica=abc1.Get();
ABC& seconda_statica=abc2.Get();
// e tutte le altre inizializzazioni che vogliamo
Nelle altre unità di compilazione sarà possibile usare i riferimenti
qua creati.
Mi rendo conto che cmq tutto questo comporta numerosi problemi: 
- dover stare attenti al parametro fittizio del template
- impone un leggero overhead per la chiamata a funzione
- il codice è più disordinato, in quanto, alla fin fine, le variabili
  non sono definite nel proprio modulo di competenza ma tutte nello
  stesso modulo
- è necessario usare i default ctor, oppure fornire delle proprie
  versioni del template
- probabilemente altri che ora non mi vengono in mente.
Nonostante tutto questo è un metodo portabile e, da quel che ho
provato io (DJGPP) funziona. Cosa ne pensate? E' pura follia?
Anto
--
Antonio Cuni, 18 anni, studente
Brainbench Certification: 
Master C++: 4.6, higher than 98% of all previous test takers.
C Language: 3.32, higher than 79% of all previous test takers.
http://www.brainbench.com/transcript.jsp?pid=1301688

Mi sembra una tecnica un po' rischiosa, perche' richiede notevole
disciplina da parte dei programmatori. Mi sembra preferibile allora
rendere esplicito l'identificatore dell'istanza statica desiderata sotto
forma di parametro della funzione ed usare un contenitore adeguato. Se
sai a priori quante istanze vuoi puoi usare un'array:
const int numIstanze = 5;
class A {};
A & getIstanza(int i) {
  static A array[numIstanze];
  if ( i >= numIstanze )
    throw "Out of range";
  return array[i];
}
Altrimenti puoi usare un contenitore stl e creare le istanze
dinamicamente.
Ciao,
Nicola


hai ragione, cos' è molto meglio. Ma allora perchè sento spesso dire
che non esiste un modo portabile per determinare l'ordine di
inizializzazione?


inizializzazione?
Dove e' che lo senti dire ? In realta' ci sono diversi sistemi di
risolvere il problema dell'ordine di inizializzazione e sono piu'
o meno adatti a seconda della versatilita' che ti serve (ad esempio
ci sono anche problemi di interdipendenza fra istanze statiche in
fase di distruzione ?) e di quanto sei disposto a pagare in
termini di complessita' (immagino concorderai sul fatto che
scrivere codice complesso quando bastava una soluzione semplice
e' inutile e dannoso).
Come capita quasi sempre non esiste una soluzione al problema
che sia la migliore sotto tutti i punti di vista... dipende
dal contesto.
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

Dove e' che lo senti dire ? In realta' ci sono diversi sistemi di
su it.comp.lang.c++ :-)
a parte gli scherzi, mi sembrava di averlo letto qualche tempo fa (se
ti ricordi c'era stato un lungo thread sull'argomento), ma
evidentemente ho preso lucciole per lanterne: chiedo venia!
