Newsgroup: it.comp.lang.c++
Titolo: Reference, operatore -> e distruttori

Ciao a tutti,
dando una ripassata al 12 capitolo di "Thinking in C++" di Bruce Eckel, 
mi sono imbattuto nel seguente esempio in cui viene realizzato una 
specie di iteratore (chiamato SmartPointer) che scorre una collezione di 
oggett, l'overloading dell'operatore "->" permette di ottenere 
l'elemento corrente della collezione.
#include <iostream>
#include <vector>
using namespace std;
class Obj
{
	static int i,j;
	public:
		~Obj() { cout << " -- Obj destructor!!! -- " << endl; }
		void f() { cout << i++ << endl; }
		void g() { cout << j++ << endl; }
 
};
int Obj::i = 12;
int Obj::j = 31;
//ObjContainer class;
class ObjContainer
{
	vector<Obj*> a; //vector of pointers-to-Obj
	public:
		void add(Obj* o)
		{
			a.push_back(o);
		}
		friend class SmartPointer;
};
//SmartPointer class --> this is the iterator;
class SmartPointer
{
	ObjContainer& oc;
	int index;
	public:
		SmartPointer(ObjContainer& objcon) : oc(objcon)
		{
			index = 0;
		}
		bool operator++()
		{
			if (index>=oc.a.size())
			{
				return false;
			}
			if (oc.a[++index]==0)
			{
				return false;
			}
			return true;
		}
		bool operator++(int) { return operator++(); }
		Obj* operator->() { return oc.a[index]; }
};
Ora, per testare il funzionamento del mio SmartPointer ho creato una 
ObjCollection. Il primo approccio è stato questo (con commenti):
int main() {
int sz = 10;
Obj ov[sz];
ObjContainer oc;
for (int j=0; j<sz; j++)
{
	oc.add(&ov[j]);
}
SmartPointer sp(oc);
do
{
	sp2->f();
	sp2->g();
} while(sp++);
//qui si vede la chiamata ai distruttori dei vari oggetti di classe Obj
return 0;
}
...ma un approccio "alternativo" potrebbe essere:
int main() {
int sz = 10;
ObjContainer oc;
for (int j=0; j<sz; j++)
{
	Obj o;
	oc.add(&o);
	//qui si vede la chiamata al distruttore di o;
}
SmartPointer sp(oc);
do
{
	sp2->f();
	sp2->g();
} while(sp++);
return 0;
}
Ovviamente la differenza tra i due approcci è "lampante" in quanto nel 
primo tutte le instanze di Obj vengono "distrutte" alla fine 
dell'esecuzione del main, mentre nel secondo ogni singolo "o" viene 
distrutto subito dopo la sua inizializzazione. Ma allora la reference 
"&o" che viene passata a oc.add(&o), cosa referenzia? Quale è la 
differenza tra i due approcci?
Grazie mille,
Giulio
-- 
OnAir: Ark - "Burn the Sun"

 Quale è la differenza tra i due approcci?
il secondo è sbagliato ;-)
ciao,
Marco

 il secondo è sbagliato ;-)
LOL!
Hai ragione, ho fatto proprio una domanda del cavolo (o almeno l'ho 
strutturata male, dai)! ;-)
Volevo dire: come posso ottenere lo stesso risultato?
Per chiarirmi meglio, cambio un po'  l'esempio che ho postato. Ora le 
istanze di Obj non hanno più due membri statici ma uno statico (i) e uno 
di istanza (j). Ecco il codice:
#include <iostream>
#include <vector>
using namespace std;
class Obj
{
	static int i;
	int j;
	public:
		Obj(int jj) { j=jj; }
		~Obj() { cout << " -- Obj destructor!!! -- " << endl; }
		void f() { cout << "i=" << i++ << endl; }
		void g() { cout << "j=" << j << endl; }
 
};
int Obj::i = 0;
//ObjContainer class;
class ObjContainer
{
	vector<Obj*> a; //vector of pointers-to-Obj
	public:
		void add(Obj* o) { a.push_back(o); }
		friend class SmartPointer;
};
//SmartPointer class;
class SmartPointer
{
	ObjContainer& oc;
	int index;
	public:
		SmartPointer(ObjContainer& objcon) : oc(objcon) { index = 0; }
		bool operator++()
		{
			if (index>=oc.a.size())
			{
				return false;
			}
			if (oc.a[++index]==0)
			{
				return false;
			}
			return true;
		}
		bool operator++(int) { return operator++(); }
		Obj* operator->() { return oc.a[index]; }
};
Come faccio, per i che va da 0 a (sz-1) a mettere nel mio ObjContainer 
degli oggetti di Obj che hanno i=0, ...etc..., (sz-1) rispettivamente, 
evitando i dangling pointers (presenti nelle righe sotto)?
int main()
{
const int sz = 5; ObjContainer oc;
for (int i=0; i<sz; i++)
{
	Obj o(i);
	oc.add(&o);
}
SmartPointer sp(oc);
do
{
	sp->f();
	sp->g();
}while (sp++);
return 0;
}
Ciao e grazie mille per la risposta!
Giulio
-- 
OnAir: Ark - "Noose"

 evitando i dangling pointers (presenti nelle righe sotto)?
potresti usare gli Smart Pointer (termine usato in accezione diversa
da quella di Eckel)
http://en.wikipedia.org/wiki/Smart_pointer
se è questo quello che intendi chiedere
ciao,
Marco
P.S. attenzione a non usare auto_ptr assieme a vector

 P.S. attenzione a non usare auto_ptr assieme a vector
Tranquillo, per ora non so neanche di cosa tu stia parlando ;-)
Ciao e grazie mille,
Giulio
-- 

 potresti usare gli Smart Pointer
[cut]
Sto andando avanti sempre sul libro di Eckel e c'è qualcosa che non mi 
quadra. Nel capitolo successivo si parla di "new" e "delete" - e fin qui 
ci siamo - da applicare agli array. Ora, supponiamo di avere:
class Foo
{
	int n;
	public:
		Foo(int seed) { n = seed; }
		~Foo() { cout << "cleaning-up Foo object with " << n << "..." << endl; }
		int getSeed() { return n; }
		void setSeed(int seed) { n = seed;}
};
e di voler inizializzare un vettore di 5 elementi con seed crescente da 
0 a 4.
Se inizio con un:
Foo* fooarray = new Foo[5]
automaticamente viene richiamato un costruttore di default che, 
peraltro, non esiste.
Ok, aggiungo il costruttore di default Foo(), e i 5 Foo vengono 
inizializzati con valore di Foo.n casuale. Per ridefinire gli elementi 
nel vettore cosa devo fare?
Ciao e grazie,
Giulio
--
OnAir:

 nel vettore cosa devo fare?
ehrm... si, cioè...
cosa posso fare oltre a:
Foo* fa2[l];
for (int i=0; i<l; i++)
{
	fa2[i] = new Foo(i);
}
? oppure questo è l'unico modo (che, tra parentesi, tanto schifo nemmeno 
fa)?
Ciao,
Giulio
-- 
OnAir: