Newsgroup: it.comp.lang.c++
Titolo: Problema di design (segue...)

Avrei altri dubbi sulle risposte che mi sono state gentilmente fornite
al precedente messaggio.
In particolare:
nella sua risposta Pescio mi consiglia un certo design, dicendo però
che c'era ancora qualcosa che andava contro le sue raccomandazioni (e
me lo lasciava da trovare come esercizio). Io ho trovato alcuni
possibili "errori", ma non sono sicuro di aver trovato quello che
intendeva lui. Qualcuno ha qualche idea in proposito? 
Inoltre con un tale design (e seguendo la logica con cui è stato
fatto) sarebbe lecito derivare da UniformRandomGenerator una classe
con più funzioni membro ognuna delle quali restituisse un valore
casuale con diversa distribuzione (ad es. una funzione membro per una
distribuzione gaussiana, una per l'esponenziale negativa etc...)
piuttosto che derivare una classe per ogni distribuzione?
Infine Alex Martelli mi chiedeva:
"mi devi spiegare perche` e percome sia "piu` comodo" chiamare una
singola funzione globale, che non "istanziare" ecc:
    double y = UniformRV(10).GetNum();
        rispetto a
    double z = UnaTuaClasse::GetNum();
"
ora mi spiego: innanzitutto l'istanziare una classe ogni volta che mi
serve un valore casuale mi sembra troppo: se questo accadesse in un
ciclo l'overhead sarebbe eccessivo.
La risposta sembra semplice: istanziare la classe prima di entrare nel
ciclo e dentro al corpo del ciclo chiamare solo la funzione.
E' vero: in questo caso sarebbe semplice. Ma nel mio contesto una
soluzione simile sarebbe difficile da applicare:
io ho una classe (diciamo Simulazione) che ha una lista di puntatori
ad un'altra classe (diciamo EventNotice). 
La classe EventNotice esporta una funzione membro chiamata Evento().
Io derivo da EventNotice diverse classi, ad esempio la classe
Arrivocliente, la classe Servicliente etc... ognuna con il suo metodo
Evento() ridefinito. 
La lista contenuta in Simulazione contiene puntatori a delle istanze
di Arrivocliente, Servicliente etc... e Simulazione possiede un metodo
per richiamare ordinatamente il metodo Evento() di ognuna di queste
istanze. 
Il problema sta qui: mi serve generare numeri casuali con
distribuzioni di diverso tipo all'interno dei metodi Evento(): ad
esempio all'interno di Arrivocliente::Evento() mi potrebbe servire UN
valore casuale uniformemente distribuito tra 0 e 10, all'interno di
Servicliente::Evento() un valore casuale con distribuzione gaussiana
etc... 
Anche accettando l'overhead che deriverebbe dall'istanziare una classe
ogni volta che mi serve UN valore casuale ci sarebbe un altro
problema: io avrei anche bisogno (per ogni tipo di generatore) di
inizializzare il generatore di numeri casuali che utilizzo all'interno
della mia classe (cioè dovrei chiamare srand() ) e questo andrebbe
fatto ragionevolmente nel costruttore della classe; ma se ogni volta
che mi serve un numero casuale istanzio una classe, viene chiamato il
costruttore che chiama srand(). Risultato: un generatore di numeri
casuali che genera sempre lo stesso numero!
GRAZIE
Daniele.

casuali che genera sempre lo stesso numero!
Soluzione triviale: la classe ha uno static bool chiamato initialized,
che parte a false, e il costruttore esegue qualcosa come:
    if(!initialized) {
        srand();
        initialized=true;
    }
E` il classico "one-time switch" -- che si trovi in un contesto di classe,
invece che di "funzioni libere", non cambia molto.
Esistono, naturalmente, soluzioni piu` "eleganti", basate sulle
(modeste, ma importanti) garanzie che il C++ ti offre rispetto
alle inizializzazioni di oggetti con lifetime statica.  Puo` darsi
che ti convenga esplorarle.  Ad esempio, definisci una classe
ausiliaria:
struct RandomInitializer {
    RandomInitializer() { srand(); }
};
e metti un oggetto statico di questa classe nel file sorgente
nel quale implementi il costruttore della classe base; questo
ti risparmia il test su initialized a ogni costruttore e quindi puo`
accelerare le cose (FORSE: non fare MAI ottimizzazioni
"alla cieca"... *MISURA*, se le prestazioni sono davvero cosi`
importanti, e verifica anche [cosa che in questo caso io non
ho ancora fatto] che le misure siano corrette, esaminando,
generalmente, il codice assembler generato...!).
Comunque, tutto questo non si applica perfettamente al tuo
caso, perche`, mi pare di avere gia` capito, devi potere avere
diverse sequenze di numeri casuali, indipendenti, in diverse
classi (o, in diversi oggetti?) -- non e` quindi ammissibile che
tutti "deleghino" la generazione di numeri casuali all'unico
generatore "globale".  Ti sono gia` stati suggeriti generatori
migliori -- di essi, puoi tenere copie separate (per classe, o
per oggetto, che sia), e quindi curare in modo assai diverso
la inizializzazione (o l'esplicito ripristino, quando vuoi garantire
certe generazioni *ripetibili* di sequenze).
D'altronde, spero che le cose principali di questa discussione
tornino utili comunque:
1. non dare per scontato di saper intuire quali prestazioni
    ha un certo costrutto! *MISURA* le alternative...!!!
2. in particolare, non farti spaventare da "istanziare una classe"
3. considera first-time switch espliciti (o, come ottimizzazione,
    costrutti C++ analoghi ma forse piu` eleganti) per i problemi di
    inizializzazione
4. qui non e` emerso, ma...: l'ottimizzazione prematura e` la
    radice di MOLTI mali...:-).
Alex