[programmazione] Allocazione e pulizia della memoria in C++

Area di discussione libera.

Moderatore: Staff

Regole del forum
1) Rispettare le idee altrui.
2) Evitare le offese dirette.
3) Leggere attentamente le risposte ricevute
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.
Rispondi
Bart
Staff
Staff
Messaggi: 4249
Iscritto il: lun 9 ago 2004, 0:00
Località: Rimini

[programmazione] Allocazione e pulizia della memoria in C++

Messaggio da Bart »

Ciao,
ho creato questo ciclo in C++:

Codice: Seleziona tutto

for(int j=0;j<the_set3->size();j++){
 esempio[j]=the_set3->get_example(j);
 for(int i=0;i<dimPCA;i++){
  vett_a(i)=esempio[j].example[i].att;
 }
 VecSet_a.Add(vett_a);
}
dove esempio è allocato così:

Codice: Seleziona tutto

svm_example* esempio = new svm_example();
e svm_example è:

Codice: Seleziona tutto

typedef struct svm_example{
  SVMINT length;
  svm_attrib* example;
  SVMFLOAT y;
  SVMFLOAT alpha;
} SVM_EXAMPLE;
Ora io vorrei sapere come usare delete per cancellare tutta la memoria allocata per esempio e esempio[j]->example. Praticamente la domanda è: "Date le strutture sopra indicate, per deallocare la memoria allocata con esempio e esempio->example come dovrei usare delete?" Al momento non ho definito distruttori e quindi se faccio: "delete esempio" cancello solamento la memoria allocata per esempio[0] e non per ogni esempio[j]->example. Se faccio "delete []esempio" ottengo degli errori in fase di esecuzione.
Spero di essere stato il più chiaro possibile. Grazie. ;)

Simone_R
Linux 2.x
Linux 2.x
Messaggi: 218
Iscritto il: mar 12 apr 2005, 0:00
Contatta:

Re: [programmazione] Allocazione e pulizia della memoria in

Messaggio da Simone_R »

Bart ha scritto: }[/code]
dove esempio è allocato così:

Codice: Seleziona tutto

svm_example* esempio = new svm_example();
e svm_example è:

Codice: Seleziona tutto

class svm_example{
public:

  svm_example() {  example = 0 ;}
~svm_example(){ if (example != 0) delete []  example ; } // distruttore
  SVMINT length;
  svm_attrib* example;
  SVMFLOAT y;
  SVMFLOAT alpha;
} SVM_EXAMPLE;
Non usare le strutture ma usa le classi.

Definisci una funzione membro distruttore ~svm_example() che verrà automaticamente chiamata quando chiami il delete su un oggetto di tipo svm_example o quando la funzione termina.

E anche un costruttore svm_example() che inizializza il campo example come vuoto (Uguale a zero).

Forse funziona anche con le struct (Ma non ricordo .... )
Verifica la sintassi (Ho scritto a memoria :D )

Ciao.

Avatar utente
lamarozzo
Linux 3.x
Linux 3.x
Messaggi: 732
Iscritto il: gio 14 lug 2005, 0:00
Desktop: xfce
Distribuzione: archlinux
Località: Roma

Messaggio da lamarozzo »

Da quel che vedo mi sembra che ci sia un errore.

esempio viene allocato semplicemente come un puntatore
a svm_example e non come array. L'allocazione dovrebbe essere così

Codice: Seleziona tutto

svm_example *esempio=new svm_example[the_set3->size()]
Per questo quando fai delete[] esempio ti dà errore.

Dal tuo codice non sembra però che esempio ti serva come
un vero e proprio array, forse potresti usarlo semplicemente
come puntatore semplice

Codice: Seleziona tutto

for(int j=0;j<the_set3->size();j++){ 
 esempio=the_set3->get_example(j); 
 for(int i=0;i<dimPCA;i++){ 
  vett_a(i)=esempio.example[i].att; 
 } 
 VecSet_a.Add(vett_a); 
}
dipende dall'utilizzo che ne fai dopo.

Per quanto riguarda la deallocazione devi andare invece in ordine inverso.
Cioè prima deallochi gli example e poi esempio.

Codice: Seleziona tutto

for (j=0;j<;j++)
{
  delete [] esempio[j].example;
}
delete[] esempio;
Per fugare ogni dubbio ti consiglio inoltre di usare Valgrind, che
è anche pacchettizzato su slacky. E' un programma che ti aiuta
a scovare tutti i memory leak in un programma.

Bart
Staff
Staff
Messaggi: 4249
Iscritto il: lun 9 ago 2004, 0:00
Località: Rimini

Messaggio da Bart »

Grazie per le risposte, siete stati chiarissimi. Ho un altro dubbio. Visto che ogni tanto nel programma ottengo errori di accesso ad aree di memoria sto cercando di vagliare tutte le possibili cause. Il mio dubbio: è se creo degli oggetti in questa maniera

Codice: Seleziona tutto

CNFloatVectorSet vecSet_a
, dove CNFloatVectorSet è una classe con tanto di distruttore, devo poi lanciare un delete vecSet_a o non è necessario?

Avatar utente
lamarozzo
Linux 3.x
Linux 3.x
Messaggi: 732
Iscritto il: gio 14 lug 2005, 0:00
Desktop: xfce
Distribuzione: archlinux
Località: Roma

Messaggio da lamarozzo »

L'operatore delete va usato "solo" quando l'oggetto è stato creato
dall'operatore new. Nel tuo caso l'oggetto verrà distrutto automaticamente
non appena uscirà di scope. A presto ;)

Avatar utente
simplex
Linux 2.x
Linux 2.x
Messaggi: 327
Iscritto il: mer 27 lug 2005, 0:00
Slackware: current
Desktop: xfce
Contatta:

Messaggio da simplex »

Quoto lamarozzo e come ti ha consigliato Simoe_R, usa le classi, sono molto piu' gestibili dele strutture, e anche il main() diventa piu' fico 8)

Bart
Staff
Staff
Messaggi: 4249
Iscritto il: lun 9 ago 2004, 0:00
Località: Rimini

Messaggio da Bart »

lamarozzo ha scritto:Per fugare ogni dubbio ti consiglio inoltre di usare Valgrind, che
è anche pacchettizzato su slacky. E' un programma che ti aiuta
a scovare tutti i memory leak in un programma.
Purtroppo sto usando visual c++ su XP e quindi il programma in questione non va bene. Ne conosci altri per caso?

Avatar utente
lamarozzo
Linux 3.x
Linux 3.x
Messaggi: 732
Iscritto il: gio 14 lug 2005, 0:00
Desktop: xfce
Distribuzione: archlinux
Località: Roma

Messaggio da lamarozzo »

purtroppo (o per fortuna, dipende dai punti di vista) non sono
pratico di ambiente microsoft. Sicuramente però Visual Studio
(come ogni buon ambiente di sviluppo)
includerà qualche debugger per la memoria, prova a spulciare la
documentazione. In bocca al lupo ;)

Simone_R
Linux 2.x
Linux 2.x
Messaggi: 218
Iscritto il: mar 12 apr 2005, 0:00
Contatta:

Messaggio da Simone_R »

Bart ha scritto:Grazie per le risposte, siete stati chiarissimi. Ho un altro dubbio. Visto che ogni tanto nel programma ottengo errori di accesso ad aree di memoria sto cercando di vagliare tutte le possibili cause. Il mio dubbio: è se creo degli oggetti in questa maniera

Codice: Seleziona tutto

CNFloatVectorSet vecSet_a
, dove CNFloatVectorSet è una classe con tanto di distruttore, devo poi lanciare un delete vecSet_a o non è necessario?
Non è necessario (se l'oggetto è statico):

Il distruttore viene, in ogni caso, chiamato in modo automatico al termine della funzione che contiene l'oggetto.

Attento se all'interno della tua classe (come descritta sopra) allocchi un oggetto dinamico questo non verrà distrutto in modo automatico se non definisci un distruttore che lo fa esplicitamente.

Il distruttore automatico chiama in modo automatico e ricorsivo SOLO i distruttori dei campi statici.

Codice: Seleziona tutto

class pincopallino {
MyClass *dyn ; // campo dinamico
MyClass bho ; // campo statico 
}

int fun() {
pincopallino  xxx ;

xxx.dyn = new MyClass() ;

......

return 1;
// xxx.dyn NON viene distrutto
}

Bart
Staff
Staff
Messaggi: 4249
Iscritto il: lun 9 ago 2004, 0:00
Località: Rimini

Messaggio da Bart »

Ok SImone_R, però se io ho una classe PincoPallino, che alloca memoria al suo interno con un new e creo un distruttore che cancella appositamente tutto ciò che viene allocato (sempre con new), se creo un oggetto statico (pincoPallino oggetto)non serve comunque che chiami il distruttore, vero? In teoria il distruttore viene chiamato quando termina lo scope e si libererà anche la memoria allocata con new dal costruttore della classe. Comunque penso di aver risolto un po' di memory leaks, grazie veramente a tutti. ;)

Simone_R
Linux 2.x
Linux 2.x
Messaggi: 218
Iscritto il: mar 12 apr 2005, 0:00
Contatta:

Messaggio da Simone_R »

Bart ha scritto:Ok SImone_R, però se io ho una classe PincoPallino, che alloca memoria al suo interno con un new e creo un distruttore che cancella appositamente tutto ciò che viene allocato (sempre con new), se creo un oggetto statico (pincoPallino oggetto)non serve comunque che chiami il distruttore, vero?
Giusto
Bart ha scritto: In teoria il distruttore viene chiamato quando termina lo scope e si libererà anche la memoria allocata con new dal costruttore della classe. Comunque penso di aver risolto un po' di memory leaks, grazie veramente a tutti. ;)
Non in teoria ma in pratica ...... (in new vanno distrutti esplicitamente ... nel distruttore ... )

Bart
Staff
Staff
Messaggi: 4249
Iscritto il: lun 9 ago 2004, 0:00
Località: Rimini

Messaggio da Bart »

Scusatemi, un'ultima domanda sempre sul tema. Se io ho un oggetto pluto della classe PincoPallino

Codice: Seleziona tutto

PincoPallino* pluto = new PincoPallino()
e faccio un "delete pluto", nel caso in cui dovessi riutilizzare pluto, magari per inserirgli nuovi dati, devo ridichiararlo? Cioè devo fare

Codice: Seleziona tutto

pluto = new PincoPallino()
oppure

Codice: Seleziona tutto

PincoPallino* pluto = new PincoPallino()
?

Avatar utente
lamarozzo
Linux 3.x
Linux 3.x
Messaggi: 732
Iscritto il: gio 14 lug 2005, 0:00
Desktop: xfce
Distribuzione: archlinux
Località: Roma

Messaggio da lamarozzo »

E' giusta la prima soluzione, nel secondo caso
il compilatore dà errore perchè ci sarebbero due variabili con lo stesso nome all'interno dello scope.
Comunque, non è una pratica molto comune.

;)

Rispondi