Visualizzazione dei risultati da 1 a 9 su 9
  1. #1

    [C++]Classi, Costruttori e Allocazione dinamica

    Salve a tutti. Studio da qualche mese il C++ e al momento avrei dei dubbi che google non e' riuscito ancora a togliermi.
    Vi posto il sorgente (funzionante e scritto da me) riguardo le liste linkate che ho creato per capire come funzionano le classi e nello specifico il rapporto che lega i costruttori con le funzioni di allocazione new/delete.
    codice:
    #include<stdlib.h>
    #include<stdio.h>
    #include <iostream.h>
    
    class BOX
    {
          public:
                 int* valore;
                 BOX* p_next;
          BOX()
          {
                 cout<<"Costruzione BOX"<<endl;
                 valore = new int(-1);
                 cout<<"Fine Costruzione BOX"<<endl;
          };
          ~BOX()
          {
                 cout<<"Distruzione BOX"<<endl;
                 delete valore;
                 cout<<"Fine Distruzione BOX"<<endl;
          };
    };
    class LISTA
    {
          public:
                 int* n_valori; //contatore di quanti valori sono stati inseriti
                 BOX* start; //punta al primo valore della lista
                 BOX* temp; //scatola aggiunta volta per volta
          LISTA()
          {
                 cout<<"Costruzione LISTA"<<endl;
                 n_valori = new int(0);
                 temp = new BOX;
                 cout<<"Fine Costruzione LISTA"<<endl;
          };
          ~LISTA()
          {
                  cout<<"Distruzione LISTA"<<endl;
                  delete n_valori;
                  delete temp;
                  cout<<"Fine Distruzione LISTA"<<endl;
          };
    };
    int main (void)
    {
        
        int *scelta;
        LISTA lista;
        scelta= new int;
        lista.start = lista.temp; //il puntatore START conserva l'indirizzo di memoria della prima box
        cout <<"Inserire quanti numeri si vogliono inserire: "<<endl;
        cin >> *scelta;
    // MEMORIZZAZIONE BOXs
        for ((*lista.n_valori)=0; (*lista.n_valori)<*scelta; (*lista.n_valori)++)
        {    
            cout<<"Inserire il "<<(*lista.n_valori)+1<<" valore: ";
            cin>> *lista.temp->valore;
            cout<<endl;
            lista.temp->p_next = new BOX;
            lista.temp=lista.temp->p_next;
        }
        delete scelta; // dealloco scelta perche' non mi interessa conservarla
    // FINE MEMORIZZAZIONE BOXs
        scelta= new int(0); // utilizzo il puntatore scelta allocando una grandezza int per utilizzarlo nel ciclo for
        lista.temp = lista.start; //punto all'inizio della lista creata
        for (*scelta=0; *scelta<*lista.n_valori; (*scelta)++) // ciclo for che stampa il valore e segue il puntatore
        {
            cout<<(*scelta)+1<<" valore: "<<*lista.temp->valore<<endl;
            lista.temp=lista.temp->p_next;
        }
        delete scelta; //dealloco scelta
        delete lista.temp->p_next; // questo delete mi richiama il distruttore BOX...e fin qui...posso anche capirlo
        delete lista.temp; // mi aspetto che venga chiamato il distruttore LISTA...e invece e' sempre BOX...
    system("PAUSE");
    Leggendo in giro per internet ho notato che in molti non colgono l'importanza dei costruttori dei distruttori.
    Sostanzialmente ho capito che i costruttori servono ad inizializzare le variabili e ad allocare memoria. Ma perche' i distruttori? (so che dealloca ma...)
    nel distruttore della classe LISTA per esempio io ho
    codice:
                 
    n_valori = new int(0);
    temp = new BOX;
    e se volessi soltanto deallocare n_valori per esempio e non temp? non potrei farlo perche' quando uso il delete di un puntatore viene richiamato il distruttore corrispondente andando a cancellarmi anche temp!
    che differenza c'e' tra dichiarare i costruttori e i distruttori come ho fatto io e, invece, inizializzare le variabili nelle dichiarazioni e allocarle/deallocarle all'interno del main...??
    e' come se mi sfuggisse la vera importanza dei costr/distruttori!
    Altra cosa:
    ogni volta che immetto un nuovo valore viene definita una nuova BOX e quindi vengono eseguiti i rispettivi costruttori (faccio stampare a monitor delle stringhe per capirlo meglio), ma quando chiamo il distruttore...viene eseguito una volta sola... va bene cosi'?
    1 distruttore basta per lo stesso costruttore chiamato piu' volte?
    qualcuno mi sa dire perche' il distruttore di LISTA non viene mai chiamato anche se scrivo delete lista.temp?
    ultima domanda (per ora altrimenti il messaggio diventa troppo dispersivo):
    [B]nel momento in cui imparo a creare delle variabili allocando dinamicamente dei puntatori (che sia malloc o new non importa) non mi conviene piu' dichiarare delle variabili normalmente??
    cioe' quando non e' consigliabile creare variabili "allocate con puntatori" in favore di quelle tradizionali?
    se fossi un programmatore dichiarerei tutte la variabili "dinamicamente" in modo tale da avere sempre la possibilita' di deallocarle e risparmiare memoria...o no? o c'e' un momento in cui il classico int valore è meglio di int* valore; valore=new int.
    Spero di non aver esagerato e vi ringrazio per la risposta!
    :berto:

  2. #2

    Re: [C++]Classi, Costruttori e Allocazione dinamica

    Originariamente inviato da Monaco88
    codice:
    ...
    int main (void)
    {
    ...    
        delete lista.temp->p_next; // questo delete mi richiama il distruttore BOX...e fin qui...posso anche capirlo
        delete lista.temp; // mi aspetto che venga chiamato il distruttore LISTA...e invece e' sempre BOX...
    system("PAUSE");
    in linea di principio non dovresti occuparti di dealocare la memoria dei membri di una classe, questo compito è delegato al distruttore della classe stessa, devi per cui scrivere

    delete lista;

    eventualmente se ti occorre dealocare anche tutta la lista nel distruttore della classe scriverai
    codice:
          ~BOX()
          {
                 cout<<"Distruzione BOX"<<endl;
                 delete valore;
    
    if ( p_temp ) delete p_temp;
                 cout<<"Fine Distruzione BOX"<<endl;
          };
    Riguardo alla tua questione relativa all'opportunità di utilizzare variabili allocate dinamicamente o staticamente, sempre in linea di principio è meglio utilizzare variabili allocate staticamente, a meno che non sia strettamente non possibile, in quanto hai così la certezza che la memoria allocata venga effettivamente rilasciata quando la variabile esce dallo "scope".
    ciao
    sergio

  3. #3

    Re: [C++]Classi, Costruttori e Allocazione dinamica

    Originariamente inviato da Monaco88
    class LISTA
    {
    ...
    BOX* temp; //scatola aggiunta volta per volta
    ..
    };
    int main (void)
    {
    LISTA lista;
    ...
    delete lista.temp; // mi aspetto che venga chiamato il distruttore LISTA...e invece e' sempre BOX...
    }
    [/CODE]

    qualcuno mi sa dire perche' il distruttore di LISTA non viene mai chiamato anche se scrivo delete lista.temp?
    • lista.temp è un puntatore a BOX, perciò quando fai delete lista.temp, viene chiamato il distruttore di lista.temp che è appunto il distruttore di BOX, non di LISTA;
    • In ogni modo quando fai delete lista.temp nella main sbagli perché stai distruggendo un qualcosa che verrà distrutto nel distruttore di lista.
    • lista è una variabile locale alla funzione main: il suo distruttore viene chiamato automaticamente all'uscita del blocco in cui viene definita.


    Consigli:
    • Anche se nel codice che hai scritto, non ce n'è bisogno, dichiara virtual i tuoi distruttori.. altrimenti quando inizierai a derivare avrai grossi grattacapi da risolvere.
    • distruggi in ordine inverso con cui hai creato.. ad esempio nel distruttore di lista
      codice:
                  delete temp;
                  delete n_valori;

    p.s. il codice che hai mandato, non è compilabile: ad esempio manca la fine della funzione main.

    EDIT: Osserva che il distruttore della variabile locale lista viene chiamato DOPO la tua chiamata a system ("PAUSE").. perciò non ne vedi l'output.

  4. #4
    Innanzitutto vi ringrazio per avermi risposto; purtroppo ho ancora qualche dubbio:
    ho capito che e' compito del costruttore deallocare le variabili...ma questo vuol dire che
    - non devo chiamarli nel main con delete se compaiono gia' nel distruttore, giusto?
    - quando il main si conclude i distruttori vengono chiamati automaticamente?

    non ho capito invece il senso di
    codice:
    if ( p_temp ) delete p_temp;
    - cioe' l'if che cosa verifica?
    (virtual me lo studio ora nei distruttori quindi evito di postare domande)
    (il codice non e' compilabile perche' ho saltato nel copia/incolla una "}" dopo il system("PAUSE"))
    Dunque ritorna il mio dubbio principale da cui e' nato tutto:
    nel momento in cui alloco ad esempio due variabili nel costruttore, mentre sono nel main non posso scegliere di deallocarne una sola? tipo
    codice:
    class OPERAZIONE
    {
          public:
                   int* addendo;
                   int* somma;
          OPERAZIONE()
          {
                   addendo = new int(0);
                   somma = new int(0);
           }
           ~OPERAZIONE()
          {
                   delete somma;
                   delete addendo;
           };
    };
    Mettiamo per esempio che il mio algoritmo debba calcolare la somma di due dati da input tastiera e che successivamente debba stampare a video il doppio della somma, quindi:
    somma+=addendo;
    stampa somma*2;
    posso deallocare solo addendo prima di somma*2?
    o meglio, se volessi deallocare addendo prima di somma*2???, non potrei farlo perche':
    - non sono io a dover distruggere qualcosa che verrà distrutto nel distruttore della classe.
    - se scrivo delete addendo; poi viene chiamato il distruttore deallocandomi pure la somma...??
    come si fa?
    Vi chiedo scusa se non ho ancora ben capito, ma con il malloc potevo liberare la memoria in qualunque momento...mentre con il new all'interno di una classe...bhe...faccio confusione
    (lo si era capito, mi sa)

  5. #5
    Originariamente inviato da Monaco88
    I
    codice:
    if ( p_temp ) delete p_temp;
    - cioe' l'if che cosa verifica?
    se vuoi deallocare tutta una lista linkata devi dealocare anche tutti gli elementi che seguono l'elemento, nel tuo caso p_temp.
    Per farlo prima verifichi che questo elemento esista (non sia cioè NULL, che rappresenta normalmente la fine della lista) e se l'elemento esiste alloro deallochi la sua memoria. Questo si propaga ricorsivamente su tutta la lista, fino alla fine.
    if ( p_temp ) verifica appunto che p_temp non sia NULL in quanto in C tutto quello che non è NULL (cioè zero) è true, se lo ritieni più chiaro lo puoi scrivere come if ( p_temp != NULL ) .. .
    ciao
    sergio

  6. #6
    scusa il refuso ma naturalmente non è p_temp che non è membro di BOX ma si tratta di p_next;
    spero di non averti fatto confusione
    ciao
    sergio

  7. #7
    Utente di HTML.it L'avatar di KrOW
    Registrato dal
    Feb 2009
    Messaggi
    281
    Ciao . . . Allora i costruttori e i distruttori vengono richiamati automaticamente . . . Il costruttore viene richiamato quando l' oggetto viene definito, quando viene allocato tramite allocazione dinamica o (in caso di oggetti statici) all' inizio del programma . . . Ognuna di queste 3 istruzioni, ha come effetto la chiamata a un costruttore :
    codice:
    OPERAZIONE op;
    OPERAZIONE* op1 = new OPERAZIONE;
    OPERAZIONE op2 = op;
    Il distruttore, viceversa, viene richiamato quando si esce dalla visibilità dell' oggetto, quando si dealloca un oggetto precedentemente allocato con new o (in caso di oggetti statici) quando il programma termina . . . Per quanto riguarda il tuo problema, sinceramente non ho capito quale sia . . .
    C++ 4ever
    496e2062696e6172696f206e6f6e2063692061767265737469 206e656d6d656e6f2020726f7661746f203a29

  8. #8
    ora le cose sono un po' piu' chiare...
    quello che non ho capito e':
    con malloc e free io sono libero di deallocare in ogni momento una variabile per poter riutilizzare lo stesso indirizzo di memoria per altre cose.
    con new all'interno dei costruttori questo non lo posso fare perche' devo aspettare per forza che il distruttore si chiami automaticamente.
    A questo punto non capisco l'importanza di allocare memoria...a sto punto dichiaro delle variabili normali...
    sara' forse un errore concettuale ma io penso all'allocazione (e quindi alla deallocazione) quando devo usare una variabile che poi per tutto il resto del programma non mi servira' piu'...e quindi la uso e poi la dealloco.
    con il new nel costruttore io non sono libero di deallocarla quando la voglio perche' ci pensa il distruttore a deallocare...
    A questo punto che differenza c'e' tra int* prova= new int(0) e un int prova=0 se poi entrambe cessano di esistere quando cessa lo scope (una per via del distruttore...l'altra per i meccanismi tradizionali)???
    Spero di essere stato chiaro... perche' una risposta non l'ho trovata da nessuna parte...tutti mi dicono cos'e' un costruttore...cos'e' l'allocazione dinamica...ma non mi aiutano a chiarire questo mio dubbio.
    Se volete posso postare due codici-esempio per esplicitare il tutto.
    grazie comunque a tutti per le risposte

  9. #9
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Guarda che anche con new e delete puoi deallocare quando vuoi. Il distruttore serve a garantire il recupero delle risorse. (Qualcuno ha detto paradigma RAAI? )
    Un esempio minimale.
    (In sign ci sono FAQ sull'argomento.)
    codice:
    class Buffer {
    	public:
    		Buffer (int size) {
    			sz__ = size;
    			pippo = new char[sz__];
    		}
    
    		~Buffer () {
    			destroy();
    		}
    
        void realloc(int size) {
        	char* tmp = new char[size];
        	delete[] pippo;
        	pippo = tmp;
        	sz__ = size;
        }
    
        void destroy() {
        	delete[] pippo;
            pippo = 0;
        }
    
              private:
    		char* pippo;
    		int sz__;
    };
    
    Buffer buffA(128);
    buffA.resize(256);
    
    Buffer buffB(512);
    buffB.destroy();
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.