Newsgroup: it.comp.lang.c++
Titolo: Eccezioni (altra persona, altra domanda)

Non centro nulla con l'autore del precedente messaggio, ed infatti il mio
problema è diverso...
Da quello che ho capito il bravo programmatore di c++ per la gestione
delle eccezioni crea una classe derivata da std::exception e la lancia al
momento giusto con un suo costruttore. Io che sono una pippa per il
momento mi accontento di creare una classe base (non derivata da
exception). Guardate questo codice:
------------------
#include <iostream>
#include <string>
using namespace std;
class Errore
{
 public:
 int codice;
 char *info, *file;
 Errore(int code, char* stringa)
 {
  char *temp =__FILE__, *filetemp = temp;
  for(int i = strlen(temp); i >= 0; i --)
  {                                      
   if (temp[i]=='/')
   {
    filetemp = temp + i + 1;
    break;
   }
  }
  file = new char[strlen(filetemp)];
  strcpy(file, filetemp);
  codice = code;
  info = new char[strlen(stringa) + 1];
  strcpy(info, stringa);
 }
 ~Errore()
 {
  delete file;
  delete info;
 }
 void report();
};
void Errore::report()
{
 cout << "codice: " << codice << "\nInfo: " << info << endl;
 cout << "Nel file " << file << endl;
}
int main()
{
 try
 {
  throw Errore(11, "Ciccio");
 }
 catch(Errore& e)
 {
  e.report();
 }
 system("PAUSE");
 return 0;
}
----------------
Peccato che quando chiamo e.report() la variabile codice esiste ancora,
mentre stampando le strighe si ha una stringa vuota (presumibilmente
perchè delete ha fatto il suo dovere). Ma com'è possibile che questo
codice chiami il distruttore ma non esegua automaticamente la distruzione
delle variabili nello stack specifiche di quell'istanza di classe (che
evidentemente il programma vuole distruggere, visto che chiama il
distruttore)?

 }
Se allochi con 'new[]', devi rilasciare con 'delete[]'.
Max

 distruggere, visto che chiama il distruttore)?
Il distruttore viene chiamato sia nel copiare l'oggetto temporaneo
Errore nella variabile "e", sia quando la variabile "e" esce di
scope.
In generale, quando una variabile allocata sullo stack viene
disallocata, lo stack pointer viene ripristinato al valore precedente
alla allocazione, ma lo stack non viene sovrascritto, quindi potrebbe
contenere ancora i dati dell'oggetto appena distrutto. Semplicemente
il linguaggio non garantisce che cosa ci sia sullo stack, e gli
implementatori di compilatori cercano di generare il codice che
minimizza il lavoro pur garantendo quello che specifica il linguaggio.
Tuttavia, questo discorso non si applica al tuo caso. Infatti,
quando l'oggetto temporaneo viene copiato nella variabile "e",
viene implicitamente chiamato il costruttore di copia di default, che
copia correttamente la variabile "codice", ma si limita a copiare i
puntatori "info" e "file", senza duplicare le aree puntate da
tali puntatori. Quando l'oggetto temporaneo viene distrutto, tali
puntatori sono invalidi.
Probabilmente un'implementazione preferibile e' la seguente:
#include <iostream>
#include <string>
using namespace std;
class Errore
{
	const int codice;
	const string info;
	string file;
public:
	Errore(int code, const char* stringa):
		codice(code), info(stringa)
	{
		string temp(__FILE__);
		string::size_type pos = temp.rfind('/');
		file = pos == string::npos ? temp : temp.substr(pos + 1);
	}
	void report() const;
};
oppure, rinunciando a togliere la directory dal nome di file:
#include <iostream>
using namespace std;
class Errore
{
	const int codice;
	const char *info, *file;
public:
	Errore(int code, const char* stringa):
		codice(code), info(stringa), file(__FILE__) { }
	void report() const;
};
Nella prima soluzione, la classe string, avendo semantica di valore,
gestisce correttamente la copia.
Nella seconda soluzione, i puntatori puntano ad aree statiche e a sola
lettura, per cui l'aliasing e' valido.
-- 
	Carlo Milanesi
 
http://digilander.libero.it/carlmila