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

    [C++] Distruttori e chiusura file

    ciao!

    ho una domanda probabilmente banale sui distruttori in c++.
    l'esempio qua sotto usa qt, ma la mia domanda è generica.
    ho questa classe:
    codice:
    ReadHeaderTable::ReadHeaderTable(QString f) {
        file = new QFile(f);
        file->open(QFile::ReadOnly | QFile::Text);
    }
    
    QStringList ReadHeaderTable::setHeader() {
        QStringList list;
        if (file->isOpen()) {
            while(!file->atEnd()) {
                list.append(file->readLine().replace("\n", ""));
            }
        }
        return list;
    }
    
    ReadHeaderTable::~ReadHeaderTable() {
        file->close();
    }
    non fa nulla di particolare.
    ho messo la chiusura del file nel distruttore.
    poi richiamo il tutto così:
    codice:
        ReadHeaderTable *rht = new ReadHeaderTable(":/h_get_articoli.txt");
        header = rht->setHeader();
    facendo così il file viene chiuso in automatico, e quindi le risorse liberate, o devo fare altro??

  2. #2
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,462
    Sì, mas dovresti prevedere le eccezioni, ad esempio la situazione in cui, per vari motivi, il costruttore non è riuscito ad aprire il file e il costruttore tenta di chiuderlo.
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  3. #3
    ciao!

    si hai ragione.
    il metodo open ritoran un bool.
    quindi in teoria mi basterebbe controllare se il file è aperto.

    però ho provato ad usare le eccezioni in questo modo:
    codice:
    ReadHeaderTable::ReadHeaderTable(QString f) {
        file = new QFile(f);
        try {
            file->open(QFile::ReadOnly | QFile::Text);
        } catch (const std::exception& e) {
            qDebug() << e.what();
        }
    }
    
    QStringList ReadHeaderTable::setHeader() {
        QStringList list;
        if (file->isOpen()) {
            while(!file->atEnd()) {
                list.append(file->readLine().replace("\n", ""));
            }
        }
        return list;
    }
    
    ReadHeaderTable::~ReadHeaderTable() {
        try {
            file->close();
        } catch (const std::exception& e) {
            qDebug() << e.what();
        }
    }
    ho passato un file errato.
    ma non è stato stampato nulla a video.
    come se non fosse andato in eccezione-

  4. #4
    No attenzione, stai leakando memoria alla grande.
    codice:
        file = new QFile(f);
    Se a livello di classe hai QFile *f e ci assegni un QFile allocato con la new è tua responsabilità deallocarlo con delete dentro il distruttore. In questo caso comunque semplicemente non ha senso allocare il QFile con la new: semplicemente dichiara a livello di classe il QFile come oggetto e non come puntatore (tra l'altro, il QFile si chiude automaticamente al momento della distruzione, quindi non serve neanche la chiamata a close).

    Idem qui:
    codice:
        ReadHeaderTable *rht = new ReadHeaderTable(":/h_get_articoli.txt");
        header = rht->setHeader();
    se poi non fai delete rht non verrà richiamato il distruttore di ReadHeaderTable, e quindi non verrà né chiuso il file, né deallocata la ReadHeaderTable.

    Con i widget di Qt e in generale con i QObject la situazione è un po' più complicata perché, con il discorso dei parent, se un oggetto è marcato come figlio di un altro gli oggetti "padre" si occupano di deallocare automaticamente i figli anche se questi sono allocati dinamicamente. Leggi http://doc.qt.io/qt-5/objecttrees.html, e in generale cerca di studiare al meglio i concetti di ownership e la differenza tra avere membri puntatori allocati dinamicamente e avere direttamente membri oggetti. Sono concetti fondamentali in C++, e se fai confusione rischi di leakare memoria o cercare di usare oggetti già distrutti.
    ho passato un file errato.
    ma non è stato stampato nulla a video.
    come se non fosse andato in eccezione-
    Gli oggetti Qt non tirano eccezioni. Leggi la documentazione:
    Opens the existing file handle fh in the given mode. handleFlags may be used to specify additional options. Returns true if successful; otherwise returns false.
    Amaro C++, il gusto pieno dell'undefined behavior.

  5. #5
    ciao MItaly!

    ok, più o meno ho capito.
    sicuramente è un concetto che devo approfondire.

    cmq, seguendo i tuoi consigli, dovrebbe bastare questo:
    codice:
    ReadHeaderTable::ReadHeaderTable(QString f) {
        file.setFileName(f);
        if (file.exists()) {
            file.open(QFile::ReadOnly | QFile::Text);
        }
    }
    
    QStringList ReadHeaderTable::setHeader() {
        QStringList list;
        if (file.isOpen()) {
            while(!file.atEnd()) {
                list.append(file.readLine().replace("\n", ""));
            }
        }
        return list;
    }
    poi richiamo il tutto così:
    codice:
    ReadHeaderTable rht(":/h_get_articoli.txt");
    header = rht.setHeader();
    l'ho provato, e sembra funzionare.

    però a questo punto mi sorge un dubbio.
    sempre dove richiamo ReadHeaderTable, ho tutta una serie di componenti (seguendo gli esempi della documentazione):
    codice:
    QGroupBox *horizontalGroupBox = new QGroupBox();
    QHBoxLayout *hl = new QHBoxLayout();
    ..............
    mi trovo in una classe derivata, che estende una classe base di tipo QMainWindow.
    questi li dovrei deallocare uno per uno, o ci pensa il distruttore della classe base?
    codice:
    BaseWindow::~BaseWindow() {
        delete ui;
    }

  6. #6
    Se sono oggetti che poi vai ad aggiungere ai widget figli della BaseWindow quest'ultima ne acquisisce l'ownership, e quindi li dealloca; idem per i layout, di cui viene trasferita l'ownership nel momento in cui li associ ad un widget. Con i widget la cosa è piuttosto naturale, dato che se non sono aggiunti alla finestra principale li vedi come finestre top-level.

    In ogni caso, in genere è più comodo crearli direttamente già con il parent impostato
    codice:
    QGroupBox *horizontalGroupBox = new QGroupBox(this);
    Amaro C++, il gusto pieno dell'undefined behavior.

  7. #7
    Quote Originariamente inviata da MItaly Visualizza il messaggio
    Se sono oggetti che poi vai ad aggiungere ai widget figli della BaseWindow quest'ultima ne acquisisce l'ownership, e quindi li dealloca; idem per i layout, di cui viene trasferita l'ownership nel momento in cui li associ ad un widget. Con i widget la cosa è piuttosto naturale, dato che se non sono aggiunti alla finestra principale li vedi come finestre top-level.

    In ogni caso, in genere è più comodo crearli direttamente già con il parent impostato
    codice:
    QGroupBox *horizontalGroupBox = new QGroupBox(this);
    perfetto, grazie mille per le spiegazioni!!

  8. #8
    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 © 2024 vBulletin Solutions, Inc. All rights reserved.