Newsgroup: it.comp.lang.c++
Titolo: Istanze globali

Ho  la necessita' di utilizzare alcune istanze globali di classi in un
programma. Ma devo poterle inizializzare a runtime. La soluzione piu' ovvia
sarebbe usare puntatori:
A* a;
B* b;
int main(int,char**)
{
    a = new A();
    b = new B();
    ...
}
Ma questo porta a una situazione molto sgradevole: occorre dereferenziarli
ogni volta.  E  poiche' alcune di queste classi fanno uso anche di operatori
(una in particolare e' un vettore multiplo), una cosa come:
(*c)[x][y][z]
sarebbe  decisamente di sgradevole utilizzo. Quello di cui ho bisogno sono
proprio delle istanze globali, ma dichiararle staticamente, com'e' noto, non
offre garanzie  sull'ordine di inizializzazione, e soprattutto le
costruzioni vengono eseguite  *prima* di entrare in main(), mentre ho
bisogno di tener conto di parametri  sulla  linea  di comando.
Potrei mettere in ogni classe un costruttore nullo e una funzione init() da
chiamare successivamente, ma mi sembra una soluzione poco pulita. E' l'unica
o ce ne sono altre ?
Avevo  pensato  ai  reference, ma siccome occorre inizializzarli all'atto
della dichiarazione  (con l'indirizzo di una classe gia' creata) non
risolverebbero il problema...
Massimo

ogni volta.
...
Un sistema che puoi usare per facilitarti leggermente la scrittura
del codice e' utilizzare reference locali associati all'oggetto
puntato:
   class MyClass
   {
     ...
   };
   MyClass *pa,*pb;
   // Esempio 1
   void foo(MyClass& a)
   {
     a.x=3;
     a[2][3]=12;
     ...
   }
   // Esempio 2
   void bar()
   {
     ...
     MyClass& a=*pb;
     MyClass& b=*pb;
     ...
     // Qui usi a[x][y]=b.myfunc()
   }
   int main()
   {
     ...
     pa=new MyClass(...);
     pb=new MyClass(...);
     foo(*pa);
     bar();
     ...
   }
Non e' quello che chiedevi ma e' qualcosa ed e' il metodo che
uso di solito. Una alternativa piu' complessa ma che ottiene la
sintassi che stai cercando e' quella di usare una classe proxy...
   class Proxy
   {
     public:
       MyClass *a;
 
       Proxy() : a(0) { }
       ~Proxy() { delete a; }
       void Assign(MyClass *aa) { a=aa; }
       double operator[](int index) { return aa->operator[](index); }
       void myfunc(double x,int y) { return aa->myfunc(x,y); }
   };
   Proxy a,b;
   void foo()
   {
     b.myfunc(a[3],12);
   }
   int main()
   {
     a.Assign(new MyClass(...));
     b.Assign(new MyClass(...));
     foo();
     ...
   }
Gli oggetti globali li dichiari di tipo Proxy (invece che MyClass)
e una volta che hai costruito le istanze delle classi che vuoi
usare assegni queste istanze ai proxy. In pratica il proxy fa
in questo caso solo da "passacarte" ma l'efficienza e' la stessa
di usare un puntatore e "->" (visto che le funzioni di redirezione
sono inline) con pero' la sintassi piu' comoda.
Se quello che ti interessa e' pero' anche la massima efficienza di
una allocazione statica (senza quindi l'indirezione ad ogni uso)
allora credo che l'unica soluzione sia quella di avere un
costruttore "fantoccio" e un altro metodo che costruisce davvero
l'oggetto (condivido con te che non e' il massimo della vita).
HTH
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

Se A,B non sono oggetti troppo strani, dovrebbe funzionare.
Ovviamente non funziona...., quindi rimane solo il metodo dei #define ....
Infatti il reference 'a' contiene l'indirizzo a cui punta pa *prima* 
dell'inizializzazione ... ovvero punta a casaccio..

 }
Prova cosi:
#define a (*pa)
#define b (*pb)
A* pa;
B* pb;
 
int main(int,char**)
{
     pa = new A();
     pb = new B();
}
E' brutto, ma cosi' elimini tutti i problemi ( ovviamente questo ha senso 
sel il nome delle variabili e' sufficentemente lungo ! ).



la soluzione più ovvia secondo me sarebbe quella di utilizzare il
pattern Singleton, che è pensato proprio per questo genere di
esigenze... se vai sul sito che è stato segnalato un po' di tempo fa
da Andrea Ferro, se non sbaglio, troverai sicuramente più
informazioni:
http://rampages.onramp.net/~huston/dp/patterns.html
ciao

 
http://rampages.onramp.net/~huston/dp/patterns.html
Forse non hai letto bene... non mi preoccupa che di queste istanze ce ne
debba essere solo una, ma come accedervi globalmente, possibilmente con meno
sintassi possibile.
Credo che alla fine utilizzerò le classi wrapper, come qualcuno (qui e in
altri posti) mi ha proposto.
Userei l'inizializzazione differita (costruttore vuoto e funzione init()),
ma questo mi impedirebbe, tra le altre cose, di usare reference all'interno
di esse, non potendoli inizializzare.
Massimo

 di esse, non potendoli inizializzare.
usa i puntatori al posto dei reference, li inizializzi a 0 nel
costruttore e poi gli assegni il valore corretto in init()!
Sinceramente, data la situazione, non riesco  a vedere grandi
alternative!

 [....]
E se provassi a fare semplicemente:
namespace impl
{
    A* a;
    B* b;
}
// non sono sicuro si possa fare qui o se debba essere
// fatto all'interno di main (dopo il new)
A& a = *impl::a;  
B& b = *impl::b;
int main(int, char**)
{
    impl::a = new A();
    impl::b = new B();
 
    // ... uso di a e b
    delete impl::a;
    delete impl::b;
}
??
Ciao
Manlio Perillo

 B& b = *impl::b;
Ho l'impressione che, come già fatto notare, farlo così farebbe puntare i
reference all'indirizzo a cui punta il puntatore non inizializzato.
Farlo nel main dopo l'allocazione funzionerebbe, ma le variabili temo che
sarebbero ben poco globali, dovendo dichiararle locali al main()...
Massimo


Questo non è un problema.
Le 'vere' variabili globali sono impl::a ed impl::b.
Quello che resta da fare è la 'scocciatura' di dover ridefinire in
ogni
scope diverso:
    A& a = *impl::a;
    B& b = *impl::b;
Ciao
Manlio Perillo