Newsgroup: it.comp.lang.c++
Titolo: Singleton e memory leak

Ciao,
voglio usare un singleton nella mia applicazione ed ho una domanda su un
problema di memoria.
// Singleton.h file
class Singleton
{
    public:
        void Dummy() {}
        static Singleton* Instance();
    protected:
        Singleton();
    private:
        static Singleton* _instance;
};
// Singleton.cpp file
#include "Singleton.h"
Singleton* Singleton::_instance = 0;
Singleton* Singleton::Instance ()
{
        if (_instance == 0)
            _instance = new Singleton;
        return _instance;
}
void TestSingleton()
{
    Singleton::Instance()->Dummy();
}
Ok, qua siamo sicuri che questo oggetto sara´ creato solo alla prima
chiamata della routine TestSingleton().
Tutte le altre volte non ci saranno piu´ altre creazioni dell´oggetto
singleton, ma continueremo ad usare l´oggetto creato la prima volta.
Ora la domanda:
in questa implementazione c´e´ l´operatore new ma chi e´ che fa la delete
dell´ ogetto?
Non so se la memoria allocata dinamicamente e´ automaticamente liberata dal
sistema operativo quando il mio programma termina o se questo e´ dipendente
dal sistema operativo.
In teoria il mio singleton puo´ essere molto grande se aggiungiamo
appropriati data members, allora forse e´ meglio aggiungere una funzione
membro pubblica che libera la memoria e verra´ chiamata dal codice cliente
oppure aggiungere la delete nel distruttore della mia classe Singleton (che
pero´ non so se verra´ mai chiamato???)
Mauro

Quando termina l'esecuzione del programma tutta la memoria
 da esso usata viene liberata, quindi non ci sono problemi
di memory leak con un singleton implementato in questo modo.
Tuttavia potrebbero esserci altri tipi di problemi.
Infatti un singleton potrebbe avere un distruttore non banale,
che debba liberare certe risorse non liberate automaticamente
dal sistema operativo, (per esempio potrebbe dover cancellare
dei file, o registrare qualche informazione da qualche parte).
Per risolvere questo inconveniente ci sono diverse tecniche.
Una di queste consiste nel registrare tutti i singleton in
un oggetto statico che contiene la lista di tutti i singleton
 e che, nel distruttore, provvede a distruggere tutti gli
oggetti nella lista.
Un'altra possibilita' consiste nel implementare i singleton
con oggetti statici (anziche' puntatori statici).
L'inconveniente e' che questi vengono instanziati anche se
nessuno li usera' mai. Inoltre non si ha il controllo
dell'ordine con cui questi verranno creati e distrutti.
Problema non secondario, specialmente se alcuni di questi
oggetti vengono usati da altri.
Un'altra soluzione consiste nel tenere un reference-counter
incrementato ad ogni instance(), e fornire un metodo
dispose() da invocare quando l'istanza non serve piu' e che
decrementa il contatore:
quando questo arriva a zero viene fatta la delete.
L'inconveniente in questo caso e' che, pur avendo al piu'
una sola istanza attiva a un certo momento, il singleton
potrebbe essere creato e distrutto piu' volte durante
l'esecuzione del programma.
Naturalmente quale meccanismo usare dipende da quali sono
le esigenze del programma.
In ogni caso bisogna stare molto attenti ai singleton e
agli oggetti statici in generale. Infatti c'e' una questione
molto delicata sull'ordine in cui vengono creati e distrutti.
Esistono comunque tecniche abbastanza sofisticate per
gestire il problema.
Saluti,
Fabio
Sent via Deja.com
http://www.deja.com/

di memory leak con un singleton implementato in questo modo.
???? Guarda che il singleton qua considerato č allocato nello heap,
con new; quindi se non si fa la delete...
secondo me il metodo piů semplice č di usare un oggetto statico nello
scope di GetInstance():
class Singleton {
public:
	static Singleton& GetIstance();
private:
	Singleton() { } // costruttore privato
};
Singleton& Singleton::GetIstance() {
	static Singleton s;
	return s;
}
in questo modo l'oggetto statico viene creato solo se realmente
referenziato.
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

--
Ciao Antonio,
grazie per la possibile soluzione al problema ma la tua implementazione ha
ancora dei problemi.
Ho avuto una risposta analoga in comp.lang.c++ ed ho risposto cosi´:
this was the Scott Meyers solution but I read this:
"It makes it hard to extend the Singleton through subclassing with this
implementation.
And It turns out that it is not possible to make thread-safe if multiple
threads can call Instance. The problem is that [some C++ compilers generate]
some internal data structures that cannot be protected by locks. In such
situations you would have to acquire the lock at the call site -- pretty
ugly."
Inoltre a coloro che rispondono che non cé´ da preoccuparsi per la memoria
da rilasciare, perche´ al termine di un programma essa e´ automaticamente
rilasciata dal sistema operativo rispondo che invece il problema c´e´.
Per correttezza bisogna sempre rilasciare la memoria prima della fine della
propria applicazione, come ovviamente vanno rilasciate tutte le risorse
allocate (e la memoria e´ per l´appunto una di queste risorse).
Se vi interessa andate a vedere cosa dicono i guru del C++ su questo
argomento all´indirizzo:
http://lib.stat.cmu.edu/~lamj/sigs/c++-report/cppr9606.c.vlissides.html
Saluti
Mauro

Personalmente penso che sia importante garantire che il distruttore di
ciascun singleton venga sempre chiamato, non solo perche' ad esso puo'
essere collegato il rilascio di risorse non automaticamente liberate dal
sistema operativo, ma piu' in generale perche' e' ragionevole da parte
di chi scrive una classe aspettarsi che cio' avvenga e farci conto.
Un altro aspetto che mi pare importante e' la tendenza dei singleton a
dipendere l'uno dall'altro e quindi a richiedere non solo un preciso
ordine di costruzione, peraltro garantito sia dalla tecnica della GoF
che da quella di Meyers, ma anche un preciso ordine di distruzione. Per
ottenere questo la soluzione migliore e' racchiudere il singleton in un
puntatore intelligente con reference count.
In questo modo l'unico vincolo sull'interdipendenza tra singleton e' che
nessun singleton venga acquisito nel distruttore di un altro singleton.
Ciao,
Nicola