Newsgroup: it.comp.lang.c++
Titolo: Uso dei template nella generazione di attributi.

Ciao a tutti sono un neofita dei newsgroup e ho un quesito da porre, quindi
vengo subito al sodo:
ho definito una classe con un template del tipo:
template <class Tipo_Dati>
class Mia_Classe
{
public:
    Tipo_Dati attributo;
}
Se Tipo_Dati = int, float .... quando Mia_Classe viene distrutta la memoria
(allocata per attributo)viene rilasciata automaticamente.
Ma se Tipo_Dati e' un puntatore ad un oggetto ?
Avviene solo la distruzione del puntatore ma non la deallocazione della
memoria.
Io credevo che nel secondo caso la distruzione del puntatore provocasse la
chiamata al distruttore dell'oggetto puntato ma cosi' non e' avvenuto.
Tutto regolare se nel distruttore di Mia_Classe inserisco un "delete
attributo" (viene richiamato il distruttore dell'oggetto puntato).
In questo modo pero' la Mia_Classe funziona solo con
Tipo_Dati di tipo puntatore e non più con oggetti (se Tipo_Dati = int il
compilatore da errore perché delete si può usare solo con puntatore)
Vi ringrazio anticipatamente
Ciao Fabrizio

memoria.
[snip]
E' tutto normale.
Nel caso di puntatori ad oggetti la memoria deve essere liberata dal
cliente della classe da te definita.
Anche nella STL (es. vector<...>) funziona allo stesso modo.
Massimo


GRAZIE MASSIMO !
Credevo che nessuno mi avrebbe dato ascolto e invece ...
La tua risposta mi e' risultata un po' criptica per cui ti prego di
spiegarmi un Po di più (non conosco STL), intanto provo a esporre il
problema sotto altri termini:
Quando viene distrutto l'oggetto Mia_Classe non viene chiamato
automaticamente il distruttore di Tipo_Dati attributo (quello che tu chiami
cliente?) dove la memoria é disallocata correttamente.
Se invece nel distruttore della classe Mia_Classe inserisco "delete
attributo" allora il distruttore di attributo viene chiamato correttamente.
ecco i due esempi:
Nº 1 :
template <class Tipo_Dati>
class Mia_Classe
{
public:
    Mia_Classe() {}
    ~Mia_Classe() {}
    Tipo_Dati attributo;
}
Tutto regolare per Tipo_Dati != da puntatori.
Nº 2:
template <class Tipo_Dati>
class Mia_Classe
{
public:
    Mia_Classe() {}
    ~Mia_Classe() {delete attributo;}
    Tipo_Dati attributo;
}
Tutto regolare con Tipo_Dati = a puntatore però se uso dei dati (int,
oggetto) mi da naturalmente un errore (delete funziona solo con dei
puntatori)
Ti ringrazio e spero che qualcuno mi possa aiutare.

Vi ringrazio anticipatamente
Non so bene per cosa...;-).  Il problema 'di superficie' (dare una diversa
semantica a un template a seconda che un tipo sia o meno un puntatore)
si risolve con una feature avanzata detta 'partial specialization' (che
pero`
i compilatori attuali ancora non implementano -- almeno, non Borland C++
Builder 3 ne` Microsoft VC++ 5), ma il problema semantico profondo
resta tutto (vedi ancora la f() di cui sopra -- vorresti che funzionasse, o
ritieni accettabile che crashi il tuo processo, ad esempio?).  E non si
risolve senza un'accurata specifica da parte tua della semantica che tu
desideri (e non e` poi detto che il compilatore sia in grado di compiere
verifiche sul rispetto dei "protocolli d'uso" da te stabiliti per la classe
stessa).  In generale, mi pare che una Mia_Classe che ha-un certo
attributo per valore (compreso eventualmente il valore di un puntatore),
e quella che la possiede per owning-pointer, siano sufficientemente
diverse da meritare di essere classi (templates) separati.
Alex

...
:>E' tutto normale.
:>Nel caso di puntatori ad oggetti la memoria deve essere liberata dal
:>cliente della classe da te definita.
:>Anche nella STL (es. vector<...>) funziona allo stesso modo.
:
:Quando viene distrutto l'oggetto Mia_Classe non viene chiamato
:automaticamente il distruttore di Tipo_Dati attributo (quello che tu chiami
:cliente?) dove la memoria é disallocata correttamente.
:
:Se invece nel distruttore della classe Mia_Classe inserisco "delete
:attributo" allora il distruttore di attributo viene chiamato correttamente.
:
Come risposta alla tua domanda Alex Martelli ha dato una descrizione piu'
che esauriente del problema (mi inchino alla notevole esperienza, conoscenza
e al livello lessicale di Alex - non sto scherzando!!!!).
Giustamente, *non* puoi inserire l'istruzione [delete xxx] nel distruttore
della
classe a meno che tu non voglia specializzare la tua classe base ricavandone
una che funziona solo per puntatori ad oggetti.
Per mantenere la generalita' d'uso della classe e' necessario che la stessa
possa
liberare la memoria dell'attributo (es. int, long, double...), ma non puo'
liberare la menoria dell'oggetto (o struttura) a cui punta l'eventuale
puntatore
(es. MyObject* objHandle).
In questo secondo caso il cliente della classe (un'altra classe o una
funzione che
dove viene gestita la classe template) deve preoccuparsi di liberare la
memoria
dell'oggetto a cui punta <objHandle>.
Quindi, la classe template libera sempre la memoria relativa ad attributo
(che esso
sia int, long o puntatore), ma non libera la memoria relativa all'eventuale
oggetto.
Ti riporto un esempio di utilizzo della classe std::vector<> per due casi
che utilizzano
entrambi oggetti, ma nel secondo caso l'oggetto viene creato utilizzando la
funzione
new.
[Caso 1]
class Dimension
{
    public:
        Dimension()    {}
        virtual ~Dimension() {}
};
class MeasurementSheet
{
    public:
        MeasurementSheet()    {}
        virtual ~MeasurementSheet()
            {
                _dims.erase(_dims.begin(), _dims.end());
            }
        void    AddDimension(const Dimension& dim)
            {
                _dims.push_back(dim);
            }
    private:
        std::vector<Dimension>    _dims;
        //    in questo caso il comportamento e' analogo a quelle che
        //    si ha con una definizione di vettore come:
        //                    std::vector<int> _dims;
}
[Caso 1]
class Dimension
{
    public:
        Dimension(LPCSTR name)
        : _name(name)    {}
        virtual ~Dimension() {}
    private:
        CString _name;
};
class MeasurementSheet
{
    public:
        MeasurementSheet()    {}
        virtual ~MeasurementSheet()
            {
               while(!_dimensions.empty())
                 {
                    delete _dims.back();
                    _dims.erase(_dims.end()-1);
                }
            }
        void    AddDimension(const Dimension& dim)
            {
                _dims.push_back(new Dimension("Diametro"));
            }
    private:
        std::vector<Dimension*>    _dims;
}
in questo secondo caso la classe MeasurementSheet che e' la cliente della
classe
std::vector<> deve liberare la memoria utilizzando la funzione delete.
Quindi la classe template std::vector<> rimane generica e la gestione della
memoria allocata per eventuali oggetti deve essere attuata esternamente.
Spero che quanto detto sia in grado di chiarire i tuoi dubbi.
Massimo

