Newsgroup: it.comp.lang.c++
Titolo: R: Lista concatenata dinamica con le classi

Alex
Premettendo che mi sono inttrodotto nella discussione solo ora, e non
conosco i precedenti, per la qual cosa mi scuso, volevo solo dirvi che la
lista come quella scritta sopra e' molto utile solo per i dati definiti e le
classi.... cosi' some sono. Occhio che per usare il polimorfismo in fase di
esecuzione (puntatori a classi derivate) occorre "rifare" il tutto con
T *data;
e ve lo dico per (brutta) esperienza passata.
                       Paolo Campanella
 
pa...@mbox.ulisse.it
http://www.geocities.com/SouthBeach/Marina/8135

T *data;
Meglio ancora, basta _istanziare_ il template usando come parametro di
tipo il puntatore, invece della classe, se e quando serve!
In altri termini:
	Lista<ClasseBase> pippo;
su questo, nessun polimorfismo, ovviamente, visto che la lista
pippo contiene *per valore* degli oggetti di tipo ClasseBase;
	Lista<ClasseBase*> pluto;
su questo, altrettanto ovviamente, il polimorfismo funziona
benissimo, visto che la lista pluto contiene *puntatori* a
oggetti di tipo ClasseBase (e quindi possiamo anche metterci
puntatori a oggetti di qualsiasi tipo pubblicamente derivato
da ClasseBase).
Questo e` il criterio fondamentale di progetto dei contenitori
della libreria standard del C++, quindi e` meglio abituarcisi:
nessun puntatore nascosto o implicito -- che impedirebbe di
evitare il risultante livello di indirettezza e quindi le
possibili inefficienze relative; se si vogliono mettere nel
contenitore dei puntatori, cio` va esplicitamente dichiarato.
Gia` che ci siamo, ricordiamo che in un contenitore della
libreria standard NON si possono mettere degli auto_ptr<>
della stessa libreria (perche` non possono liberamente essere
copiati o assegnati).  Una std::list<Pippo*> va benissimo se
la "proprieta`" degli oggetti puntati e` di "qualcosa d'altro",
o se si linka un garbage collector con la propria applicazione
(in un modo o nell'altro, si evita cosi` di preoccuparsi di
quando occorra rilasciare gli oggetti); altrimenti, e`, in
tutta probabilita`, meglio usare, se servono simultaneamente
sia il polimorfismo, sia la gestione del lifetime degli oggetti,
dei puntatori intelligenti che gestiscono reference count.
Purtroppo la libreria standard non prevede questo template,
forse per difficolta` di scegliere fra design invasivo, piu`
efficiente ma intrusivo, e non-invasivo.  Comunque, ecco il
classico, "canonico", puntatore intelligente non invasivo
"all'antica":
template <class T>
class NISP {	// non-invasive smart pointer
    T* data;
    int* rc;
    void Release() { if(!--*rc) { delete data; delete rc; } }
    void AddRef() { ++*rc; }
public:
    NISP(T* p=0): data(p), rc(new int(1)) {}
    NISP(const NISP &t): data(t.data), rc(t.rc} { AddRef(); }
    ~NISP() { Release(); }
    NISP& operator=(const NISP&t) {
	if(this!=&t) {
	    Release(); data=t.data; rc=t.rc; AddRef();
	}
	return *this;
    }
    T* operator->() const { return data; }
    T& operator*() const { return *data; }
};
Questo ha l'altrettanto classico problema di non simulare
bene il comportamento dei puntatori relativamente alla
possibilita` di usare un puntatore a classe derivata dovunque
sia richiesto un puntatore alla classe base; la soluzione,
che richiede un compilatore C++ ragionevolmente aggiornato,
e` di aggiungere un metodo-template che trasformi NISP<A>
in NISP<B> se e solo se A* puo` implicitamente essere usato
come B* (occorre anche una dichiarazione di friend fatta
come template perche` qualsiasi NISP<A> possa leggere i
dati privati di qualsiasi altro NISP<B>).
Questo schema supporta qualsiasi classe T che sia correttamente
polimorfica (in particolar modo, con un distruttore virtuale,
naturalmente).  Altri schemi, pero` necessariamente piu`
invasivi, possono supportare l'uso implicito di "new T",
il copy-on-write con uso di uno schema di clonazione, ecc ecc.
Alex
--
 ____    Alex Martelli, Bologna, Italia -- email: 
al...@magenta.com
 \SM/___                                 
http://magenta.com/~alex
  \/\bi/     You never know what is enough unless you know what
     \/          is more than enough.