Newsgroup: it.comp.lang.c++
Titolo: [problemi di linker] Accidenti al pattern Singleton!!!!!!!

ciao a tutti,
per un mio lavoro ho utilizzato il pattern singleton;
Scusatemi se vi ricopio in inglese senza tradurre la parte che voglio
sottoporre alla vostra attenzione:
//--------------------------------------------------------------------------
--------------------------------
A more flexible approach uses a registry of singletons. Instead of having
Instance define the set of possible Singleton classes, the Singleton classes
can register their singleton instance by name in a well-known registry.
The registry maps between string names and singletons. When Instance needs a
singleton, it consults the registry, asking for the singleton by name. The
registry looks up the corresponding singleton (if it exists) and returns it.
This approach frees Instance from knowing all possible Singleton classes or
instances. All it requires is a common interface for all Singleton classes
that includes operations for the registry:
    class Singleton {
    public:
        static void Register(const char* name, Singleton*);
        static Singleton* Instance();
    protected:
        static Singleton* Lookup(const char* name);
    private:
        static Singleton* _instance;
        static list<NameSingletonPair>* _registry;
    };
Register registers the Singleton instance under the given name. To keep the
registry simple, we'll have it store a list of NameSingletonPair objects.
Each NameSingletonPair maps a name to a singleton. The Lookup operation
finds a singleton given its name. We'll assume that an environment variable
specifies the name of the singleton desired.
    Singleton* Singleton::Instance () {
        if (_instance == 0) {
            const char* singletonName = getenv("SINGLETON");
            // user or environment supplies this at startup
            _instance = Lookup(singletonName);
            // Lookup returns 0 if there's no such singleton
        }
        return _instance;
    }
Where do Singleton classes register themselves? One possibility is in their
constructor. For example, a MySingleton subclass could do the following:
    MySingleton::MySingleton() {
        // ...
        Singleton::Register("MySingleton", this);
    }
Of course, the constructor won't get called unless someone instantiates the
class, which echoes the problem the Singleton pattern is trying to solve! We
can get around this problem in C++ by defining a static instance of
MySingleton. For example, we can define
    static MySingleton theSingleton;
in the file that contains MySingleton's implementation.
//--------------------------------------------------------------------------
--------------------------------
Così ho fatto nel mio progrmma;
in particolare io ho su file diversi i metodi di Singleton e di MySingleton,
sul file Singleton.h e MySingleton.h le dichiarazioni, e in Singleton.cpp e
MySingleton.cpp i metodi.
Il registro,
        static list<NameSingletonPair>* _registry;
è un membro statico e va inizializzato; ovviamente lo inizializzo nel file
dei metodi del singleton, Singleton.cpp
Ovviamente
    static MySingleton theSingleton;
viene dichiarato ed istanziato in MySingleton.cpp.
Fin qui tutto bene, mi ha funzionato.
Poi un giorno ne ho dovuto implementare un altro,
    ASingleton::ASingleton() {
        // ...
        Singleton::Register("ASingleton", this);
    }
 static ASingleton theASingleton;
ovviamente nei file ASingleton.h e ASingleton.cpp;
Cosa mi è successo?
In pratica il linker mi mette
    static ASingleton theASingleton;
prima di
   static list<NameSingletonPair>* _registry;
e così theASingleton si registra in un _registry non ancora allocato, dando
ovviamente errore!!!
Visto che semplicemente il cambiare nome ad un file per farlo linkare dopo
non mi sembra una buona soluzione,
mi potete dire come posso fare per risolvere il problema?
(uso il Visual C++ 6, non so se esiste un modo per dirgli come eseguire il
link che mi può essere utile qui,
però vorrei trovare una soluzione che funzioni ovunque....)
Grazie mille!!!

Ciao,
Purtroppo non hai controllo sull'ordine in cui gli oggetti
statici non locali e in differenti unita' di compilazione
vengono inizializzati. Potresti pero' trasformare gli
oggetti statici non locali in locali sostituendo per esempio
il membro privato della classe base Singleton:
static list<NameSingletonPair>* _registry;
con una funzione la cui implementazione potrebbe essere:
list<NameSingletonPair>* Singleton::getRegistry()
{
   static list<NameSingletonPair> nspl;
   return &nspl;
}
La prima volta che la funzione viene chiamata la lista viene
creata e il puntatore restituito e' quindi valido.
Gian Michele