Devo chiudere manualmente un ifstream?


201

Devo chiamare manualmente close()quando utilizzo un std::ifstream?

Ad esempio, nel codice:

std::string readContentsOfFile(std::string fileName) {

  std::ifstream file(fileName.c_str());

  if (file.good()) {
      std::stringstream buffer;
      buffer << file.rdbuf();
      file.close();

      return buffer.str();
  }
  throw std::runtime_exception("file not found");
}

Devo chiamare file.close()manualmente? Non dovresti ifstreamusare RAII per chiudere i file?

Risposte:


251

NO

Ecco a cosa serve RAII, lascia che il distruttore faccia il suo lavoro. Non c'è nulla di male nel chiuderlo manualmente, ma non è il modo C ++, sta programmando in C con le classi.

Se si desidera chiudere il file prima della fine di una funzione, è sempre possibile utilizzare un ambito nidificato.

Nello standard (27.8.1.5 Modello di classe basic_ifstream), ifstreamdeve essere implementato con un basic_filebufmembro che detiene l'handle del file effettivo. È tenuto come membro in modo tale che quando un oggetto ifstream si distrugge, chiama anche il distruttore basic_filebuf. E dallo standard (27.8.1.2), quel distruttore chiude il file:

virtual ˜basic_filebuf();

Effetti: distrugge un oggetto di classe basic_filebuf<charT,traits>. Chiamate close().


4
+1 Non sapevo che RAII lo gestisse ... Immagino che tu impari qualcosa di nuovo ogni giorno
TStamper,

21
L'uso di un ambito nidificato solo per chiudere il file è completamente artificiale: se si intende chiuderlo, chiamare close () su di esso.

3
Tuttavia, potresti essere in grado di sostenere che limitare la durata dell'oggetto all'ambito necessario significa che non accederai accidentalmente a un ifstream chiuso. Ma è un po 'inventato.
Eclipse,

9
In C ++ gli ambiti nidificati non sono quasi mai inutili. Hanno tutto a che fare con il comportamento del codice, specialmente quando si lancia qualcosa. Se un futuro manutentore li rimuove, non conosce molto bene il C ++.
Elliot Cameron,

2
A volte è necessario chiamare close()manualmente per la gestione degli errori.
ks1322,

71

Devi chiudere il file?
NO

Dovresti chiudere il file?
Dipende.

Ti interessano le possibili condizioni di errore che potrebbero verificarsi se il file non si chiude correttamente? Ricorda che chiudi le chiamate setstate(failbit)se fallisce. Il distruttore ti chiamerà close()automaticamente a causa di RAII ma non ti lascerà un modo per testare il bit di errore poiché l'oggetto non esiste più.


14

Sono d'accordo con @Martin. Se si scrive nel file, i dati potrebbero essere ancora memorizzati in un buffer e potrebbero non essere scritti nel file finché non close()vengono chiamati. Senza farlo manualmente, non hai idea se si sia verificato un errore o meno. Non segnalare errori a un utente è una brutta pratica.


5

No, questo viene fatto automaticamente dal ifstreamdistruttore. L'unico motivo per cui dovresti chiamarlo manualmente è perché l' fstreamistanza ha un ampio ambito, ad esempio se è una variabile membro di un'istanza di classe long living.


4
Un altro motivo potrebbe essere quello di controllare gli errori di chiusura dei file e di impedire il lancio del distruttore, se sono consentite eccezioni con il flusso.
Daniel Langr,

4

Puoi permettere al distruttore di fare il suo lavoro. Ma proprio come qualsiasi oggetto RAII, ci possono essere momenti in cui la chiusura manuale può fare la differenza. Per esempio:

#include <fstream>

using std::ofstream;

int main() {
  ofstream ofs("hello.txt");
  ofs << "Hello world\n";
  return 0;
}

scrive il contenuto del file. Ma:

#include <stdlib.h>

#include <fstream>

using std::ofstream;

int main() {
  ofstream ofs("hello.txt");
  ofs << "Hello world\n";
  exit(0);
}

non lo fa. Questi sono rari casi in cui un processo termina improvvisamente. Un processo di arresto anomalo potrebbe fare simili.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.