Newsgroup: it.comp.lang.c++
Titolo: permettere una sola istanza di una classe

sembra una domanda cretina, ma ho bisogno di racchiudere delle mie routine
in una classe.
dato che non ho bisogno di utilizzare più istanze di questa classe, e ho dei
membri statici nella classe, vorrei fare in modo che sia possibile
istanziare una sola volta la classe.
ho pensato a un flag static, che nel costruttore della classe viene
controllato, ma se non viene inizializzato almeno una volta come faccio a
sapere se posso creare la classe?
--
ciao
XAERO [*]
"Se vuoi renderti conto del valore del
denaro, prova a chiedere un prestito"
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCA/CM/CS/CC/E/O d?(-) s+:-- a--->? C++++(+)$@ UL-(--) P>++ L+() E-- W+++$@
N++@ o-- K- w+++(++++)@ O--- M V? PS+++ PE-(--) Y? PGP>++ t? 5? X+ R- tv-
b+(++) DI? D++ G- e !h !r y?
------END GEEK CODE BLOCK------

sapere se posso creare la classe?
Perché non definisci tutti i mebri dato e funzione come static? In questo
modo puoi utilizzare la classe per effettuare le chiamate ai campi come se
fosse, ovviamente solo in senso figurato, un oggetto.
Ciao.
-- 
La classifica dei prodotti MS:
C#, la migliore barzelletta di Bill Gates.
Visual C++, il meno standard dei compilatori C++.
J++, la copiatura più riuscita.
Windows, il più instabile.
Visual Basic, un esempio di prodotto decente della MS - forse l'unico -.
OutlookExpress, scandali su scandali.
La classifica degli "amici" coglioni:
Stefano Zanchi, il miglior lamer del mondo.
 

istanziare una sola volta la classe.
E' un caso molto comune. Esistono diverse soluzioni standard dalla
banale alla complessa a seconda di come e' realizzata la classe e
di quando viene fatto l'accesso a questa.
Immagino pero' che esistano delle istanze statiche di altri oggetti
che possono fare riferimento alla tua classe (altrimenti non avresti
problemi a dichiarare semplicemente una istanza statica).
Se la tua classe non soffre di problemi sull'ordine *distruzione*
delle statiche (ovvero se la tua classe non si appoggia ad altre
istanze statiche durante la sua distruzione e nessuna istanza
statica ha bisogno di usare la tua classe durante la distruzione)
allora puoi usare un metodo abbastanza semplice:
  // MyClass.h
  class MyClass
  {
    public:
      static MyClass& instance();
      void f();   // esempio di metodo non static
      ~MyClass(); // distruttore pubblico
    private:
      MyClass();  // costruttore privato
  };
  // MyClass.cpp
  MyClass& MyClass::instance()
  {
    static MyClass m; // istanza statica in una funzione
    return m;
  }
  // User.cpp
  ...
    MyClass::instance().f(); // Chiama un metodo
In questo modo l'istanza della tua classe viene creata
al momento del suo primo utilizzo.
Per casi piu' complessi (interdipendenza delle istanze
statiche sia in costruzione che distruzione) esistono
diverse soluzioni un po' piu' complicate...
HTH
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

Ciao Xaero,
ricercando sul web questo tipo di
problema(
http://lib.stat.cmu.edu/~lamj/sigs/c++-report/cppr9606.c.vlissides
.
html), grazie ai guru del C++ io ho fatto cosi´:
class Singleton {
public:
 static Singleton* Instance();
protected:
 Singleton() { }
 friend class SingletonDestroyer;
 virtual ~Singleton() { }
private:
 static Singleton* _instance;
 static SingletonDestroyer _destroyer;
};
Singleton* Singleton::_instance = 0;
SingletonDestroyer Singleton::_destroyer;
Singleton* Singleton::Instance () {
 if (!_instance) {
  _instance = new Singleton;
  _destroyer.SetSingleton(_instance);
 }
 return _instance;
}
class SingletonDestroyer {
public:
 SingletonDestroyer(Singleton* = 0);
 ~SingletonDestroyer();
 void SetSingleton(Singleton* s);
private:
 Singleton* _singleton;
};
SingletonDestroyer::SingletonDestroyer (Singleton* s) {
 _singleton = s;
}
SingletonDestroyer::~SingletonDestroyer () {
 delete _singleton;
}
void SingletonDestroyer::SetSingleton (Singleton* s) {
 _singleton = s;
}
Uso la classe Singleton con la funzione membro Instance() che mi assicura
che avro´ una sola instanza della classe.
La prima volta mi alloca dinamicamente l´oggetto singleton sullo heap, e le
altre volte ritorna l´indirizzo allocato nella prima chiamata.
La classe SingletonDestroyer e´ necessaria per fare in modo di operare la
delete della Singleton che altrimenti non potrebbe mai essere fatta.
Si poteva anche realizzare Instance() in questo modo senza bisogno della
classe SingletonDestroyer:
Singleton& Singleton::Instance () {  static Singleton s;  return s; }
(Soluzione data anche dal guru C++ Scott Meyers!)
ma implementare Instance() in modo che restituisca il reference a un oggetto
singleton statico porta a problemi nel caso si voglia fare una sottoclasse e
a problemi di sicurezza nel caso si vogliano fare dei threads che usino la
Instance().
Saluti
Mauro

 sapere se posso creare la classe?
Il flag static, anche se membro della classe, sei obbligato a definirlo
esternamente e lě puoi anche inizializzarlo.
EMG

sapere se posso creare la classe?
Non ho capito bene cosa vorresti risolvere con il flag static, visto
che comunque non potresti impedire che un oggetto venga istanziato.
L'unica idea che mi viene in mente per realizzare la tua struttura é
quella di rendere il costruttore inaccessibile(quindi privato o
protetto) e di dichiarare all'interno della classe un'istanza statica
di essa che poi userai nel tuo programma principale.
Lavinia
WINWORD.EXE - ERRORE DI APPLICAZIONE
l'istruzione a "0x3017ff27"ha fatto riferimento alla
memoria a "0x02a3143c".La memoria non poteva essere 'read'.

Ad esempio:
class Once {
  public:
    Once () {
      if ( created ) throw "No 'bbuono!";
      ++created;
    }
  private:
    static int created;
};
int Once::created = 0;
Io uso questo meccanismo per una classe che viene usata come membro o
come superclasse, ma della quale non dev'essercene piu' di una.
Ciao,
Nicola


Però questo impedisce completamente di creare una nuova istanza mentre
potrebbe essere utile che istanziando un oggetto si faccia riferimento
in modo automatico all'unica istanza permessa, o sbaglio?
EMG

in modo automatico all'unica istanza permessa, o sbaglio?
cosa ne dite di questa idea che mi è venuta adesso? volendo se ne
potrebbe fare un bel template...
class singleton;
class singleton_ref {
	singleton_ref() { }
  // tutti i membri del caso
  friend class singleton;
};
class singleton {
	static singleton_ref s;
  public:
  	singleton_ref& Instance() { return s; }
};
int main() {
	singleton a,b,c;
  /* a.Instance(), b.Instance(), c.Instance()
  	 accedono tutte allo stesso oggetto */
}
Anto
--
Antonio Cuni, 18 anni, studente
Brainbench Certification: 
Master C++: 4.44, higher than 97% of all previous test takers.
Visual Basic 5: 3.06, higher than 77% of all previous test takers.
http://www.brainbench.com/transcript.jsp?pid=1301688

 }
Il BCC55 compila regolarmente ma io c'è una cosa che non capisco: ho
provato a mettere una stampa a video nel costruttore di singleton_ref ma
questa non si vede mai. Il membro s di singleton non viene quindi mai
costruito? O c'è qualcosa che mi sta sfuggendo (molto probabile)?
EMG

In effetti il mio esempio non e' un Singleton. E' una classe che si puo'
usare come classe base mix-in o come membro, ma della quale puo'
essercene una sola istanza per programma. La uso ad esempio per
implementare l'autenticazione ed il controllo dei permessi di accesso in
modo centralizzato.
Ciao,
Nicola

 };
Io continuo a preferire i singleton "puntati" o magari gestiti via smart
pointer. In effetti mi sno scritto una classe template che ne implementa
la gestione. Non la posto perche' non sono ancora del tutto convinto del
suo disegno e perche' e' molto legata al progetto su cui lavoro.
Ciao,
Nicola

 costruito? O c'è qualcosa che mi sta sfuggendo (molto probabile)?
Poiche' non ha effetti "dinamici" il costruttore di singleton_ref e'
eliminato per ottimizzazione. Puoi provare a disabilitare inlining e
ottimizazioni.
Ciao,
Nicola

Ciao Antonio,
Ho preso il tuo esempio ed ho fato delle stampe.
Sul fatto che
/* a.Instance(), b.Instance(), c.Instance()
  accedono tutte allo stesso oggetto */
sono d´accordo come si puo´ anche vedere dalle stampe.
Il fatto e´ che pero´ a b e c sono 3 distinti oggetti con 3 diversi
indirizzi come puoi vedere.
Lo stesso oggetto a cui si accede tramite Instance() e´ singleton_ref che e´
statico, ma il mio scopo e´ accedere all´unico oggetto (singleton).
Per cui se io volessi impedire di instanziare piu´ oggetti per la mia classe
singleton non ho ottenuto il mio scopo.
Ecco il tuo esempio con le stampe:
#include <iostream>
using namespace std;
class singleton;
class singleton_ref
{
   singleton_ref() {cout << "singref" << endl; }
   // tutti i membri del caso
   friend class singleton;
};
class singleton
{
   static singleton_ref s;
   public:
   singleton_ref& Instance() { return s; }
};
singleton_ref singleton::s;
int main()
{
   singleton a,b,c;
   cout << &(a.Instance()) << " " << &(b.Instance()) << " " <<
&(c.Instance()) << endl;
   cout << &a << " " << &b << " " << &c << endl;
   return 0;
}
Saluti
Mauro

 }
Ciao,
Nicola

suo disegno e perche' e' molto legata al progetto su cui lavoro.
cosa intendi per singleton "puntato"? ci sono delle controindicazioni
ad usare la soluzione da me proposta (io non ci ho ancora pensato
molto, è stata una fulminazione improvvisa :-) ?


ottimizazioni.
se non sbaglio č lo stesso problema di cui si discute nell'altro
thread (quello sui distruttori, anche se il titolo non c'entra molto
:-); oppure ho capito male?


singleton non ho ottenuto il mio scopo.
infatti io ho scritto queste classi proprio per risolvere questo
problema, che era stato proposto da Enrico Maria Giordano; si può
utilizzare anche per il tuo scopo: solo che singleton è solo una
"maschera", la classe di cui deve esserci una sola istanza deve
prendere il posto di singleton_ref; per rendere riusabile l'idea,
possiamo farne un template:
template<class T> class singleton;
class mia_classe {
	mia_classe() { } // costruttore privato
  // tutti i membri del caso
  friend class singleton<mia_classe>;
};
template<class T> class singleton {
	static T s;
  public:
  	T& Instance() { return s; }
};
int main() {
	singleton<mia_classe> a,b,c;
  /* a.Instance(), b.Instance(), c.Instance()
  	 accedono tutte allo stesso oggetto */
}
devi stare attento a dichiarare il costruttore della classe privato
(altrimenti chiunque potrà istanziarla) e renderla friend di singleton
(altrimenti nessuno potrà istanziarla)


O anche direttamente: singleton::Instance();
appunto, addio differenza fra le istanze...
a dire la verità non so se possa avere senso avere istanze diverse che
accedono ad un unico oggetto; potrebbe essere utile come no, non ci ho
ancora pensato
anto


 ottimizazioni.
Ci avevo pensato. Ma a me pare comunque un'ottimizzazione che introduce
un bug nel programma dato che ne elimina l'unico effetto visibile che
era proprio il risultato che volevo.
EMG

 era proprio il risultato che volevo.
Secondo lo standard gli unici effetti visibili sono l'output, inteso
come l'interazione con l'ambiente circostante il programma in
esecuzione, e la modifica di variabili dichiarate "volatile". Posto che
il risultato inteso come insieme di effetti visibili non venga alterato,
*tutto* il resto puo' essere ottimizzato via.
Ciao,
Nicola
P.S. Quello che vedi col debugger non fa parte degli effetti visibili
:-)

 molto, è stata una fulminazione improvvisa :-) ?
Singleton allocato dinamicamente e gestito tramite puntatori (quindi
"puntato"), magari intelligenti. Alla soluzione da te proposta e'
probabilmente preferibile il pattern dello "Stateless Proxy", presentato
su questo newsgroup da Alex Martelli parecchio tempo fa:
// Singleton.h
class Singleton {
  public:
    int f();
    double g();
};
// Singleton.cpp
namespace {
class SingletonImpl {
  public:
    int f() { return 5; }
    double g() { return 4.3; }
} si;
}
int Singleton::f() { return si.f(); }
double Singleton::g() { return si.g(); }
Confesso che mi turba un po' che "si" non sia un membro statico di
Singleton, ma in realta' non c'e' alcun motivo per cui sia visibile al
di fuori del file di implementazione di Singleton.
In questo modo uno puo' istanziare Singleton quanto vuole, con uno
spreco minimo di spazio e riferendosi di fatto ad un unico oggetto.
Anche questo funziona se non ci sono interdipendenze di inizializzazione
con altre variabili statiche.
Ciao,
Nicola

 riferirsi ad un unico oggetto.
Anche se la dichiari statica la notazione a.b() funziona lo stesso.
Ciao,
Nicola

>P.S. Quello che vedi col debugger non fa parte degli effetti visibili
Non per nulla un debugger serve per vedere i difetti invisibili! ;-)
-- 
Posted from 
adsl-21-135.38-151.net24.it
 [151.38.135.21] 
via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 problema, che era stato proposto da Enrico Maria Giordano;
Io però avrei voluto fare qualcosa del genere:
class A
{
    ???     // Che ci metto?
};
void pippo()
{
    A a;     // a è lo stesso oggetto creato nella main()
}
int main()
{
    A a;     // Viene creato un oggetto di tipo A
    return 0;
}
Non so se serva a qualcosa ma spero di aver reso l'idea.
EMG

 *tutto* il resto puo' essere ottimizzato via.
Ma io avevo messo nel costruttore uno
std::cout << "Pippo" << std::endl;
e non mi veniva visualizzato!
EMG

con altre variabili statiche.
però in questo modo non è possibile farne un template...


}
Per come l'ho scritta io è necessario usare variabili di tipo
Singleton<A> (vedi la definizione del template in un altro post di
questo thread). Se però vuoi continuare a usare la stessa sintassi
puoi fare così:
template<class T> class Singleton;
class single_A {
	single_A(); { } // PRIVATO!
	single_A(const& single_A);
	single_A& operator=();
	friend class Singleton<single_A>;
};
typedef Singleton<single_A> A;
facendo così il codice che hai scritto sopra compila e fa esattamente
quello che vuoi tu!
Purtroppo domani parto per la settimana bianca, quindi riprendereò
questo thread domenica prossima.
Ciao a tutti!


In effetti ho la sensazione che su queste cose bcc esageri, anche se non
ho fatto prove estensive.
Ciao,
Nicola

Vero e non solo, diventa anche piuttosto macchinoso estenderne le
funzionalita'.
Ciao,
Nicola

Vedi l'esempio che ho postato in un altro subthread, in risposta ad
Antonio Cuni.
Ciao,
Nicola

}
La cosa non risolverebbe il problema dello "static initialization
order". L'istanza che dichiari viene inizializzata in un momento
non meglio precisato prima dell'esecuzione di main (a meno di
complicare il discorso con le librerie dinamiche).
In particolare se qualche istanza statica usa a.Instance() non
c'e' nessuna garanzia che l'oggetto singleton sia gia' stato
costruito nel momento in cui viene acceduto.
Spesso Instance() viene implementata con
    singleton_ref& Instance()
    {
      static singleton_ref r;
      return r;
    }
oppure con
    singleton_ref& Instance()
    {
      static singleton_ref *p=new singleton_ref;
      return *p;
    }
proprio per fare in modo da essere garantiti che il ritorno
da Instance() non avvenga se non quando il singleton e' stato
effettivamente costruito (anche se la chiamata proviene
dal costruttore di istanze statiche in altri moduli).
Come template si potrebbe usare qualcosa come...
  template<class T>
  T& Singleton()
  {
    static T t;
    return t;
  }
da usare con istruzioni come
   Singleton<MyClass>().foo();
HTH
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

   Singleton<MyClass>().foo();
Questa non mi sembra una buona soluzione; il singleton dovrebbe
impedire di costruire più di una istanza, mentre in questo modo potrei
tranquillamente scrivere:
MyClass a,b,c;
e addio singleton... per risolvere bisognerebbe dichiarare costruttore
privato e Singleton<MyClass> friend di MyClass. Il problema di fondo è
che cmq questa è una soluzione troppo intrusiva e poco intuitiva.
Secondo me una tecnica per mantenere una sintassi simile a quella
normale potrebbe essere questa (che avevo già postato una settimana
fa, ma la riposto nel caso non l'aveste vista):
template<class T> class Singleton;
class single_A {
	single_A(); { } // PRIVATO!
	single_A(const& single_A);
	single_A& operator=();
	friend class Singleton<single_A>;
};
typedef Singleton<single_A> A;
Anche in questo caso il problema è sempre lo stesso. Se io possiedo
una classe di cui non posso cambiare la definizione, è possibile
renderla un singleton?
Scusate l'eccessiva prolissità del post, però avevo tante cose da
dire...


renderla un singleton?
Trovo anche questa questione senza senso... se
io "utente" possiedo gia' l'accesso ad una classe
"normale" cosa mi impedisce di costruire istanze
di questa classe direttamente ?
Inoltre a mio parere le classi non si "rendono singleton".
Con "singleton" si intende un pattern in cui si rende
disponibile l'accesso ad istanze specifiche di una
classe. Qualcosa che *permetta* a parti non correlate
di un progetto di accedere tutte ad una stessa istanza.
Quindi non si "rende singleton" una classe... al piu'
si implementa un pattern singleton con una istanza
di una classe assegnata.
Non e' che qui stai cercando di fare qualcosa
che va contro la natura stessa del C++ ?
Ad esempio private/protected in C++ secondo me *NON*
sono stati pensati per "impedire" di fare qualcosa ma
per evitare *errori accidentali*. Se si fosse voluto
cercare di introdurre l'incapsulamento per proteggersi
da chi deliberatamente vuole fare qualcosa allora
come prima cosa si sarebbero *separate* le dichiarazioni
delle parti protette/private da quelle pubbliche...
inoltre poco potrebbe (in un linguaggio come il C++)
salvare da spiritosi che giocano con typecasting e
memcpy.


 memcpy.
Esatto.
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556

memcpy.
a questo punto non si tratta più di errori accidentali ma veri e
proprio "crimini" :-)
Cmq non vedo dove sia il problema: mi pare plausibile avere una classe
di cui sia illogico creare più di un'istanza (ad esempio un oggetto
"Screen" in una GUI); in questo caso usiamo un singleton e siamo
sicuri che ci sarà una ed una sola istanza di tale classe.
