Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 12
  1. #1
    Utente di HTML.it
    Registrato dal
    Jul 2008
    Messaggi
    1,326

    [C++] metodo distruttore

    Ciao a tutti!

    Mi ritrovo con un piccolo problema di natura più concettuale che pratica che riguarda i metodi distruttori relativamente al linguaggio C++; purtroppo studio il C++ da poco più di 3 mesi e in maniera "discontinua" - causa studio di tante altre cose - e a volte finisco col farmi venire dei dubbi apparentemente banali.

    La mia domanda essenzialmente è: qual è, di preciso, lo scopo di un metodo distruttore all'interno di una classe?

    Mi spiego meglio.

    Da quello che so, un distruttore è un particolare metodo di una classe che occorre quando bisogna compiere delle operazioni esplicite per la distruzione di un oggetto come la deallocazione della memoria precedentemente allocata per un particolare campo dell'oggetto o la chiusura di uno stream aperto. Ma quello che mi chiedo è: a parte le istruzioni che vengono scritte esplicitamente nel corpo del distruttore stesso, questo esegue anche delle operazioni predefinite stabilite magari dallo standard del linguaggio?

    In estrema sintesi, avrebbe senso dichiarare (e definire) un distruttore - in una classe - esattamente come questo:

    codice:
    ~nome_classe() { };
    o sarebbe inutile?

    Nella fattispecie del mio problema, io ho implementato una classe per costruire un albero binario (per l'algoritmo di Huffman) che ha questi attributi (la classe si chiama "Nodo" e "Byte" è un carattere senza segno):

    codice:
         unsigned int peso;
         Byte valore;
         Nodo * figlio_sx;
         Nodo * figlio_dx;
    e ho definito un metodo dal nome pittoresco "distruggiAlbero()" col quale dealloco ricorsivamente lo spazio in memoria allocato per tutti i puntatori ai figli dei vari nodi dell'albero (figlio_sx e figlio_dx), dalle foglie alla radice.

    Avendo definito questo metodo, mi serve a qualcosa definire anche un distruttore standard come quello che ho scritto prima?

    Scusate se mi sono dilungato ma volevo essere quanto più chiaro possibile (e spero di esserci riuscito!)
    every day above ground is a good one

  2. #2
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381

    Re: [C++] metodo distruttore

    Originariamente inviato da YuYevon
    La mia domanda essenzialmente è: qual è, di preciso, lo scopo di un metodo distruttore all'interno di una classe?
    Garantire il cleanup delle risorse.
    Originariamente inviato da YuYevon
    In estrema sintesi, avrebbe senso dichiarare (e definire) un distruttore - in una classe - esattamente come questo:
    codice:
    ~nome_classe() { };
    Come sempre, dipende. Se non si intende ereditare dalla classe, un distruttore vuoto ha poco senso. Se però si intende derivare dalla classe, il distruttore dev'essere virtual (pena comportamento indefinito.) anche se vuoto.

    Nel tuo caso specifico, il fatto che tu abbia implementato una "distruggiAlbero()" non garantisce che all'uscita dello scope dell'oggetto, l'albero venga distrutto.
    Inserendo il metodo nel distruttore (ovviamente con i controllo che l'albero esista ancora o no.) garantisce che "distruggiAlbero()" sia invocata almeno una volta.
    Se questo sembra rindondante, occorre ricordare che l'introduzione delle eccezioni in C++ ha cambiato il modo di programmare. Se viene lanciata un'eccezione prima dell'invocazione di "distruggiAlbero()" e tale eccezione non è gestita, "distruggiAlbero()" non è mai invocata, mentre il distruttore si.
    E il concetto base del paradigma RAAI.
    Un esempio è fstream::~fstream() dove viene invocata la fstream::close()
    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.

  3. #3
    Utente di HTML.it L'avatar di KrOW
    Registrato dal
    Feb 2009
    Messaggi
    281
    I distruttori non sono altro che metodi chiamati subito prima della distruzione di un oggetto ... Se tu non definisci un distruttore in una classe, il compilatore lo farà al posto tuo col corpo vuoto. I distruttori servono soprattutto quando uno dei membri della classe è un puntatore. In caso che, durante la vita dell' oggetto, venga allocata memoria tramita il puntatore, è compito del distruttore assicurare che alla distruzione dell' oggetto venga deallocata la memoria (ovviamente in questo caso è compito del programmatore implementare correttamente il distruttore). Ad esempio nel tuo caso, ti consiglierei di sostituire il metodo distruggiAlbero() con il distruttore (o al limite fare in modo che il distruttore richiami distruggiAlbero() ) . . . Perchè se ti dimentichi di richiamare il metodo distruggiAlbero() ed il tuo oggetto esce dal suo scope (e quindi, a meno che non sia statico , viene distrutto), l' oggetto in se stesso viene distrutto ma incorri in un errore di memory leak . . . Spero di essere stato chiaro . . . Ciao

  4. #4
    Utente di HTML.it
    Registrato dal
    Jul 2008
    Messaggi
    1,326
    Grazie per le risposte!

    Comunque il punto è che il metodo "distruggiAlbero()" lo richiamo esplicitamente io (all'uscita del programma) sul nodo radice dell'albero stesso, e il metodo poi si "propaga" ricorsivamente su tutto l'albero, deallocando lo spazio ovviamente prima per i puntatori ai figli del penultimo livello dell'albero (cioè quello prima delle foglie) e poi continua verso i livelli sempre più alti fino alla radice.

    Quindi il fatto che il metodo venga richiamato è sicuro dato che sono io a richiamarlo esplicitamente. Del resto, sostituirlo con il distruttore o fare in modo che venga richiamato dal distruttore mi risulta un po' troppo difficile; in realtà lo avevo anche fatto ma la cosa mi aveva richieto un po' troppi casini (in particolare una variabile booleana dichiarata come attributo della classe che valeva false per tutti i nodi tranne che per la radice, cosa che francamente non mi piaceva per nulla).
    every day above ground is a good one

  5. #5
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Quindi il fatto che il metodo venga richiamato è sicuro dato che sono io a richiamarlo esplicitamente.
    Sicuro?
    codice:
       Albero albero;
       // codice vario di cui una funzione di libreria lancia un'eccezione.
       albero.distruggiAlbero();
    distruggiAlbero() non sarà mai invocata.

    Edit.
    Orrori di ortografia.
    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.

  6. #6
    Utente di HTML.it
    Registrato dal
    Jul 2008
    Messaggi
    1,326
    Guarda avevo già fatto delle prove in tal senso e ora ho anche riprovato mettendo delle istruzioni di stampa nel corpo del metodo in questione ed effettivamente mi vengono stampati i messaggi a video, quindi il fatto che venga richiamato è sicuro...
    every day above ground is a good one

  7. #7
    Utente di HTML.it L'avatar di XWolverineX
    Registrato dal
    Aug 2005
    residenza
    Prague
    Messaggi
    2,565
    Prova questo codice

    codice:
       Albero albero;
         throw;
       albero.distruggiAlbero();
    "Se proprio devono piratare, almeno piratino il nostro." (Bill Gates)

    "Non è possibile che 2 istituzioni statali mi mettano esami nello stesso giorno." (XWolverineX)

    http://xvincentx.netsons.org/programBlog

  8. #8
    Utente di HTML.it
    Registrato dal
    Jul 2008
    Messaggi
    1,326
    Originariamente inviato da XWolverineX
    Prova questo codice

    codice:
       Albero albero;
         throw;
       albero.distruggiAlbero();
    In questo caso il programma mi si interrompe proprio in corrispondenza dell'istruzione throw; diciamo che non è che pregiudica la chiamata al metodo, semplicemente si blocca proprio il programma, infatti se provo a mettere l'istruzione tra le prime righe si interrompe subito...

    Comunque sulla gestione delle eccezioni non sono molto preparato... lessi qualcosa dal manuale qualche tempo fa autonomamente ma non ho mai fatto alcuno studio vero e proprio in merito. All'università non c'è un vero e proprio corso sul C++, viene incluso all'interno di un altro ben più vasto... ed è per questo che non sono ferratissimo sul linguaggio, pur avendo partorito un codice di 700 righe e più proprio per questo progetto... forse anche alla luce di questo i problemi che mi pongo esulano da quelle che sono le mie competenze in merito.
    every day above ground is a good one

  9. #9
    Utente di HTML.it L'avatar di KrOW
    Registrato dal
    Feb 2009
    Messaggi
    281
    Premetto che non sono un esperto in alber binari . . . Ma se allochi i nodi dinamicamente, dal distruttore del nodo/radice è possibile cancellare i nodi foglie richiamando solo delete:
    codice:
    ~node()
    {
    if(figlio_sx)
        delete figlio_sx;
    
    if(figlio_dx)
        delete figlio_dx;
    }
    Cosí otterresti l' effetto desiderato visto che viene richiamato il distruttore di ogni nodo . . .

  10. #10
    Originariamente inviato da YuYevon
    In questo caso il programma mi si interrompe proprio in corrispondenza dell'istruzione throw;
    Sì, ma se ci fosse un catch nella funzione chiamante il programma potrebbe continuare a funzionare e l'albero non verrebbe deallocato. È così che nascono i memory leaks.
    Amaro C++, il gusto pieno dell'undefined behavior.

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.