Newsgroup: it.comp.lang.c++
Titolo: Funziona cosi il distruttore per questa classe?

Salve a tutti voi,
eccomi di nuovo qui.
Il mio dubbio è legato all'uso del distruttore per una lista.
Io ho una classe cosi definita, dove premetto che UL_int è un typedef che
definisce un alias del tipo unsigned long int :
-----------File sack_pac.h----------------
#include <list>
#include "sack_list_element.h"
using namespace std;
#define TRUE 1
#define FALSE 0
#define NOT_VALID 0
#define VALID 1
class sack_packet{
                  /....../  Variabili membro private
                  int SACK_LIST_OPTION;
                  public:
                  list<Sack_list_element> sack_list;
                  sack_packet (void);
                  sack_packet (int type);
                  sack_packet (int ID_CONN,UL_int pack_id,UL_int ack_num,
                               double t_in,double t_pack,int type);
                  sack_packet (int ID_CONN,UL_int pack_id,UL_int next_sg,
                               double t_in,double t_pack,int type,
                               UL_int first_l_e,UL_int first_r_e);
                  sack_packet (int ID_CONN,UL_int pack_id,UL_int next_sg,
                               double t_nin,double t_pack,int type,
                               UL_int first_l_e,UL_int first_r_e,
                               UL_int second_l_e,UL_int second_r_e);
                  sack_packet (int ID_CONN,UL_int pack_id,UL_int next_sg,
                               double t_in,double t_pack,int type,
                               UL_int first_l_e,UL_int first_r_e,
                               UL_int second_l_e,UL_int second_r_e,
                               UL_int third_l_e,UL_int third_r_e);
                  ~sack_packet();
                  bool operator==(const sack_packet&){
                  return(true);}
                  bool operator <(const sack_packet&){
                      return(false);}
                  int Sack_opt(void);
                  /......../ Alcuni Metodi
                  void Constructor(int type);
                  void Constructor(int ID_CONN, UL_int pack_id, UL_int
ack_num,
                             double t_start,double t_pack,int type);
                  void Create_Sack_list(int num,UL_int first_l_e,
                    UL_int first_r_e,UL_int second_l_e,UL_int second_r_e,
                        UL_int third_l_e,UL_int third_r_e);
                  };
--------------End of sack_pac.h--------------------
Gli elementi memorizzati nella lista contenuta in ogni istanza della classe
sack_pac appartengono alla classe Sack_list_element, che si trova in:
---------------File sack_list_element.h---------------
class Sack_list_element{
            UL_int left_edge;
            UL_int right_edge;
            public:
            Sack_list_element(); // Costruttore di default
            Sack_list_element(UL_int LEFT_EDGE,UL_int RIGHT_EDGE);
            bool operator==(const Sack_list_element&){
                  return(true);}
            bool operator<(const Sack_list_element&){
                  return(false);}
             // bool operator<( const sack_list_element& that ) const
 return false; }
            UL_int Left_edge(void);
            UL_int Right_edge(void);
            };
-----------End of sack_list_element.h----------------
Come avrete potuto notare ho dichiarato all'interno della classe sack_pac il
suo distruttore
~sack_packet();
Ora il mio dubbio è se e come devo chiamare il distruttore e/o liberare la
memoria occupata per la mia lista.
Quello che io ho scritto è questo,
----File sack_pac.cpp----
typedef list<Sack_list_element>:: iterator index;
/...../
sack_packet:: ~sack_packet(){
         if(!sack_list.empty())
          {
    for(index i=sack_list.begin(); i!=sack_list.end(); i++)
           sack_list.erase(i);
            }
         }
ma pare che mi da dei problemi ogni tanto.
Sto sbagliando qualcosa?
Avrei bisogno di una vostra dritta, perchè da solo non ci riesco più !!!
L'errore si manifesta durante l'esecuzione del codice, un simulatore, come
un errore del tipo:
Una finestra d'errore che dice
Fault: access violation at 0x402c75: read of address 0x1180f6e8,
e se effettuo il run nell'ambiente Borland C++ ver. 5.02 il debugger mi
indica sempre la linea blu in
if(!sack_list.empty())
oppure in:
sack_list.erase(i);
A questo che vi ho già scritto vi aggiungo anche che ho eseguito più volte
lo stesso .exe, ma non sempre il blocco si ottiene allo stesso punto di
iterazione del codice. Spessissimo il blocco dell'esecuzione è sempre nello
stesso punto, anche se mi è capitato di riavviare immediatamente il .exe
senza ottenere il blocco nel punto in cui si era avuto alla  precedente
esecuzione.
La cosa è, a mio modo di vedere, un po insolita, perchè, anche se si tratta
di un simulatore, allo stato attuale non sono presenti delle variabili che
vengono generate casualmente.... ossia ogni esecuzione dovrebbe farmi
ottenere sempre gli stessi risultati seguendo esattamente gli stessi punti
del codice.
Inoltre l'esecuzione dell'eseguivile dura mediamente oltre 20 minuti su un
333Mhz con 128 Mb, e produce in uscita un file di circa 60 Mb e cocci.
Per favore, fatemi sapere qualcosa.
Grazie in anticipo,
Sebastiano

del codice.
Una linea di codice che rientri nella definizione di "undefined
behaviour" potrebbe provocare la fuoriuscita di demoni dal tuo naso.
Oppure potrebbe non succedere nulla, ed e' questa la cosa peggiore.
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

Grazie tantissimo,
perň, visto che č in corso questa discussione volevo chiederti se si fosse
trattato di un container di puntatori come avrei dovuto usare l' i++.
Anche Max M. mi aveva fatto notare la stessa cosa.
Se devo eseguire un for la condizione di incremento la devo dare.
Forse me la caverei con un ++i ?

 Forse me la caverei con un ++i ?
Il problema con il tuo codice, come ha spiegato Andrea, era il fatto che
l'operazione di incremento a un certo punto veniva applicata a un
iteratore non più valido. Se il codice nel ciclo for non invalida
l'iteratore, non sussistono problemi.
Ricorda che erase() invalida l'iteratore, ma restiuisce un altro
iteratore. E' questo valore che andrà successivamente utilizzato per
proseguire eventualmente l'iterazione sulla lista.
Max

Grazie Max M. (una curiosità... ma M. stà per ? )...
non avevo badato al fatto che erase() restituisce un iteratore.
Bye,
Sebastiano

 #define VALID 1
Perchè la gente si ostina a usare macro dove non c'è ne è nessun
bisogno?
Fai
  const bool NOT_VALID = 0;
  const bool VALID = 1;
[TAGLIO]
Manlio Perillo

Ma questo che mi fai notare può essere causa d'errore ?
Bye,
Sebastiano


No, ma non è un buon stile di disegno.
In particolare l'uso delle macro è da sconsigliare perchè
possono provocare problemi collaterali.
Manlio Perillo

Cioč, scusami se te lo chiedo, ma quali sono gli effetti collaterali?
Comunque, se non mi sbaglio, se usassi la notazione
const int a=1;
anzichč
#define a 1
non ho una visibilitŕ di a solo all'interno del .cpp in cui adopero tale
costante, mentre con #define ho visibilitŕ su tutto il progetto?
Bye,
Sebastiano


const bool NOT_VALID = false;
const bool VALID = true;
Vero che la conversione e` automatica, ma cosi` mi pare meglio    ;-)
Paolo
-------------------------------------------
  Paolo Marotta
 
http://web.tiscalinet.it/paolo_marotta/
-------------------------------------------


Per la fretta ho preso una svista.
Volevo scrivere
  const int NOT_VALID = 0;
mi sono confuso con il bool precedente.
Comunque è meglio come hai detto tu.
Manlio Perillo

   const int NOT_VALID = 0;
Io preferisco addirittura:
class ValidityExample {
  public:
    ValidityExample() : valid(false) {}
    bool isValid() const { return valid; }
    void setValid(bool v) { valid = v; }
  private:
    bool valid;
};
Se il C/C++ fosse fortemente tipizzato anche sui tipi scalari, come il
Pascal, potrebbe aver senso introdurre costanti/enum, ma visto che sono
solo sinonimi...
Ciao,
Nicola

 ha scritto nel messaggio
news:39C5F50C...@divalsim.it...

Non capisco la cosa...
Manlio Perillo

Intendo che non mi pare particolarmente significativo definire due
costanti per rappresentare un concetto ed il suo contrario, quando il
tipo bool serve esattamente a questo.
Mi sembra piu' sensato scrivere
if ( a.isValid() )
o addirittura 
if ( valid )
che non
if ( pippo == VALID )
Ciao,
Nicola

 ha scritto nel messaggio
news:39C62DBC...@divalsim.it...

OK, mi sembra la cosa pù sensata.
Ma questa scelta implica un cambiamento profondo
di tutto il codice che usave VALID e l'opposto
(cosa che comunque consiglio a Sebastiano).
In verità avevo risposto a Sebastiano in quel modo
perchè in TUTTI i programmi C e MOLTI C++
si fa un uso sconsiderato di macro come se
const on esistesse.
Nel caso del GNU C la cosa la potrei capire
(ma non approvare).
La forza e la debolezza della filosofia GNU
è che ci lavorano molte persone nel tempo libero.
Questo significa che nessuno ha il tempo di riscrivere
codice di decadi fa in cui nel C const non esisteva.
Questo significa che il compilatore deve mantenere una
compatibilità assoluta con il passato.
(mi vengono i brividi solo a pensare di metterci mano).
La cosa gravissima è che in libri abbastanza recenti (1993)
alcuni autori utilizzino ancora il C originale.
Manlio Perillo


Grazie  Manlio Perillo

Intendo dire che per il Pascal una cosa come:
type Validity = { NOT_VALID, VALID };
e' un tipo completamente distinto da qualsiasi altro tipo scalare: non
ci sono conversioni predefinite, ecc. In questo tipo di linguaggio trovo
sensato esprimere attraverso un tipo specifico il dominio di qualsiasi
variabile, perche' il compilatore puo' aiutarti a individuare gli
errori. In C/C++ manca un supporto corrispondente:
enum Validity { NOT_VALID, VALID };
questo non e' *veramente* un tipo distinto dal tipo intero usato per
rappresentarlo (tralasciando l'ambigua definizione di come tale tipo
viene individuato). Il compilatore non da nessun supporto serio: l'enum
e' solo un raggruppamento di costanti. Anche definendo due costanti si
perde la relazione tra le due:
const int NOT_VALID = 0;
const int VALID = 1;
Il fatto di usare qualcosa di diverso da bool non da vantaggi concreti.
In realta' nella maggior parte dei casi con i quali mi sono scontrato
l'uso di typedef e' utile in solo due casi:
Per nascondere dettagli di una specifica piattaforma in codice che deve
essere portabile;
All'interno di template, per definire tipi dipendenti dai parametri del
template.
Ciao,
Nicola

 e' solo un raggruppamento di costanti.
Comunque non si può assegnare uno scalare ad un Validity.
  Validity guest;
  guest = 0;   // errore
Questa cosa mi sembra sufficiente per la ricerca di errori.
Manlio Perillo

alcuni autori utilizzino ancora il C originale.
Forse perche' non e' cosi' evidente in C il vantaggio come in C++.
Considera che da un lato il C e' meno tipizzato del C++, e dall'altro molta
gente se ne "approfitta" ( io per primo ), per cui si vedono quelle cose che
fanno passare la notte in bianco a Wirth : un puntatore a funzione passato
in un int, double convertiti al volo in char, char promossi a puntatore ....
Non so chi sia la causa o l'effetto sta di fatto che molti programmatori di
questa liberta' non ne vogliono fare a meno.
In C++ il discorso e' diverso: il linguaggio e' _molto_ piu' complesso e la
tipizzazzione e' un valido aiuto ( pensate ai template ). Per questo l'uso
dei const va incoraggiato.
Personalmente utilizzo moltissimo le macro perche'... sono stupide : il
compilatore neanche le vede, ci pensa il preprocessore.


Io appena vedo un header pieno di una caterva di macro una dopo
l'altra mi sento male.
A volte mi è capitato di avere miei nomi che coincidevano
con il nome di una macro.
Inoltre per evitare nomi semplici si fa
  DIRECTX_API_WINDOWS_NOREPLAY
(che cosa orrenda).
In C++ si possono usare i namespace per evidenziare
la struttura.
namespace windows
{
  namespace api
  {
     namespace directX
     {
        const action_type noreplay;
     }
  }
}
In questo modo se possibile si possono usare
le direttive using oppure
  windows::api::directX::noreplay
Manlio Perillo

la struttura.
E' indubbio che i namespace se ben utilizzati sono un eccellente aiuto. 
Ma il punto NON e' questo. Se io utilizzo il C, mi posso permettere il lusso
di certe "porcherie". In C++ ( a meno che non voglia utilizzarlo come C
evoluto ) e' molto piu' pericoloso.

evoluto ) e' molto piu' pericoloso.
Non e` che in C++ e` piu` pericoloso, semplicemente i rischi delle
"porcherie" sono piu` evidenti perche` il compilatore li segnala.
In C gli effetti sono identici, solo che il compilatore non te li
segnala.


segnala.
Sul discorso degnalare ci sarebbe molto da "disquisire". Premesso che le 
mie esperienze si basano sull'egcs; ma trovo molto piu' chiare le
segnalazioni in C che in C++ ( questo perche' il linguaggio e' molto piu'
complesso ). Comunque basta attivare i warning al massimo ed hai tutte le
segnalazioni che vuoi anche in C.

mie esperienze si basano sull'egcs; 
Qui dipende molto dalla bonta` del compilatore, il borland ad esempio
x me era molto piu` chiaro del vc++!


x me era molto piu` chiaro del vc++!
Perche' ( sulla falsariga di quello che state gia' facendo sull'aderenza
allo standard da parte dei compilatori ) non ci si organizza su dei test per
la "qualita'" dei messaggi di errore ?

la "qualita'" dei messaggi di errore ?
Perche` le mie giornate sono di 24 ore, comprese quelle per il
sonno!!!
E poi oggi VC++ mi ha combinato un bello scherzetto, una schermata
blu sotto NT come non le vedevo da anni, con tanto di memory dump
(assolutamente non riuscita) e perdita di ore di lavoro (ha azzerato
un file di progetto e tagliatone almeno un altro)!
Il tutto per la semplice compilazione di un file di pochi KB.
<sfogo on>
Speriamo che succeda anche a Guglielmo de Cancellis con qualcosa
di molto grosso, cosi` si decidera` a fare le cose come si deve
(sempre che ne sia capace... e ne dubito)!
</sfogo off... to be continued>
