Newsgroup: it.comp.lang.c++
Titolo: Pattern Factory...

Ciao a tutti,
il mio problema non riguarda proprio il pattern Factory della GoF, però ne è
una conseguenza...
Supponiamo di avere una classe F con il compito di creare un oggetto di
classe opportuna, derivata da un opportuna interfaccia I:
class F {
I* GetClass() const;
};
class I {
void f() = 0;
};
class A : public I {
... // ridefinizione di f();
};
class B : public I {
... // ridefinizione di f();
};
la funzione F::GetClass() ha il compito di scegliere la classe più opportuna
tra A e B. Ma devo proprio restituire l'oggetto per puntatore? E' abbastanza
brutto, perchè devo creare dinamicamente l'oggetto dentro F::GetClass() e
poi è il cliente che lo deve deallocare (leggi: presto o tardi *memory
leak* ).
Esiste un altro modo?
GRAZIE
Daniele.

 Esiste un altro modo?
Certo, puoi benissimo ritornare uno *smart pointer* (o altro tipo di
handle) che si occupera` di "deallocare" l'oggetto quando non serve
piu`.  La gamma delle possibilita` va dal semplicissimo auto_ptr<>
al sofisticato concetto di *restituire alla fabbrica* l'oggetto che
non serve piu` in modo che *si occupi LEI* di "distruggere" (o magari
RICICLARE...) l'oggetto in funzione di come esattamente lo aveva
costruito.  Normalmente userai il reference-count per sapere quando
e` che un oggetto "non serve piu`".
Di reference count son piene le fosse, quindi mi limito a mostrare
uno schema semplificato relativo a "restituire alla fabbrica"
supponendo che questo sia fatto direttamente.
template<class T, class F=MyFactory<T> >
class ptr {
    friend class F;
    F& f;
    T* pT;
    int* prc;
    ptr(T* pT, F& f): f(f), pT(pT), prc(new int(1)) {}
public:
    ~ptr()
        if(0==--*prc) {
            delete prc;
            f.giveback(pT);
        }
    }
    ptr(const ptr& p): f(p.f), pT(p.pT), prc(p.prc) {
        ++*prc;
    }
    T* operator->() { return pT; }
    const T* operator->() const { return pT; }
    T& operator*() { return *pT; }
    const T& operator*() const { return *pT; }
};
Spero che l'idea di base sia chiara.  ptr<> non e`
assegnabile, poiche` contiene un reference, ma
solo inizializzabile.  Una tipica factory sarebbe
ad esempio (semplificando un po'!-):
template<class T>
class MyFactory {
    friend class ptr<T>;
    void giveback(T* p) { delete p; }
public:
    ptr<T> makeone() { return ptr<T>(new T, *this); }
};
ma si puo` anche avere, sempre semplificando:
template<class T>
class RecyclingFactory {
    friend class ptr<T, RecyclingFactory>;
    std::list<T*> available;
    void giveback(T* p)
        p->clear();
        available.push_back(p);
    }
    // non implementare:
    void operator=(const RecyclingFactory&);
public:
    ptr<T, RecyclingFactory> makeone()
        T* p = 0;
        if(available.empty()) {
            p = new T;
        } else {
            p = available.back();
            available.pop_back();
            p->reset();
        }
        return ptr<T, RecyclingFactory>(p, *this);
    }
    ~RecyclingFactory() {
        std::list<T*>::iterator it = available.begin();
        while(it != available.end()) {
            delete *it;
            ++it;
        }
    }
    RecyclingFactory(const RecyclingFactory&) {}
};
dove supponiamo che T abbia una funzione membro
".clear()" che "rimette a nuovo" un oggetto,
liberandone tutte le risorse che sia il caso
di liberare, e una ".reset()" che lo rimette
nello stato iniziale, ri-acquisendo le risorse
che potrebbero servire.
Ci sono parecchi piccoli dettagli che cosi` a braccio
forse non ricordo con precisione su questa pattern
(uno che ho ricordato e` il copy ctor fittizio, che
NON copia la lista available...!-), ma e` da tenere
presente che, come ottimizzazione, questa funziona
molto bene con oggetti di un tipo T che puo` essere
costoso da costruire/distruggere, soprattutto se si
adeguano alla pattern "two-phase construction,
two-phase destruction" (tali sono in pratica la
clear e reset suddette...).  Si potrebbero naturalmente
(e come al solito) 'estrarre' questi aspetti in una
classe traits che faccia da parametro separato alla
factory, ecc, ecc.
Alex