Trebuie să închid manual un ifstream? (Programare, C++, Ifstream, Raii)

Edison Gustavo Muenz a intrebat.

Trebuie să apelez manual la close() atunci când folosesc un std::ifstream?

De exemplu, în codul:

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");
}

Trebuie să apelez file.close() manual? Nu ar trebui să ifstream să se folosească de RAII pentru închiderea fișierelor?

5 răspunsuri
Eclipse

NU

Pentru asta este RAII, lăsați destructorul să-și facă treaba. Nu este nimic rău în a-l închide manual, dar nu este modul C++, ci programarea în C cu clase.

Dacă doriți să închideți fișierul înainte de sfârșitul unei funcții, puteți folosi întotdeauna un domeniu de aplicare imbricate.

În standard (27.8.1.5 Class template basic_ifstream), ifstream trebuie să fie implementat cu un basic_filebuf membru care să conțină mânerul efectiv al fișierului. Acesta este deținut ca membru astfel încât, atunci când un obiect ifstream se destructurează, acesta apelează și destructorul de pe basic_filebuf. Și, conform standardului (27.8.1.2), acel destructor închide fișierul:

virtual ˜basic_filebuf();

Efecte: Distruge un obiect din clasa basic_filebuf<charT,traits>. Cheamă close().

Comentarii

  • +1 Nu știam că RAII se ocupă de asta…cred că în fiecare zi înveți ceva nou –  > Por TStamper.
  • 26

  • Utilizarea unui domeniu de aplicare imbricate doar pentru a închide fișierul este complet artificială – dacă intenționați să îl închideți, apelați close() pe el. – anon
  • Deși, ați putea argumenta că limitarea duratei de viață a obiectului la domeniul de aplicare necesar înseamnă că nu veți accesa accidental un ifstream închis. Dar acest lucru este un pic artificial. –  > Por Eclipse.
  • În C++, sferele imbricate nu sunt aproape niciodată inutile. Ele au totul de-a face cu comportamentul codului, în special atunci când ceva aruncă. Dacă un viitor responsabil cu mentenanța le elimină, înseamnă că nu cunoaște C++ foarte bine. –  > Por Elliot Cameron.
  • Uneori este necesar să apelați close() manual pentru gestionarea erorilor. –  > Por ks1322.
Martin York

Trebuie să închideți fișierul?
NU

Ar trebui să închideți fișierul?
Depinde.

Vă interesează posibilele condiții de eroare care ar putea apărea dacă fișierul nu se închide corect? Rețineți că apelurile de închidere setstate(failbit) dacă nu reușește. Distrugătorul va apela close() pentru dvs. în mod automat, datorită funcției RAII dar nu vă va lăsa o modalitate de a testa partea de eșec, deoarece obiectul nu mai există.

Mark Edwards

Sunt de acord cu @Martin. Dacă scrieți în fișier, este posibil ca datele să se afle în continuare într-un buffer și să nu fie scrise în fișier până când close() este apelată. Fără a face acest lucru manual, nu aveți nicio idee dacă a existat sau nu o eroare. A nu raporta erorile unui utilizator este o practică foarte proastă.

Dimitri C.

Nu, acest lucru este făcut automat de către ifstream destructor. Singurul motiv pentru care ar trebui să îl apelați manual este că fstream instanța are un domeniu de aplicare mare, de exemplu, dacă este o variabilă membră a unei instanțe de clasă cu viață lungă.

Comentarii

  • Un alt motiv ar putea fi pentru a verifica erorile de închidere a fișierelor și pentru a preveni aruncarea destructorului, în cazul în care excepțiile sunt permise cu fluxul. –  > Por Daniel Langr.
ericcurtin

Puteți permite destructorului să își facă treaba. Dar, la fel ca în cazul oricărui obiect RAII, pot exista momente în care apelarea manuală a închiderii poate face diferența. De exemplu:

#include <fstream>

using std::ofstream;

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

scrie conținutul fișierului. Dar:

#include <stdlib.h>

#include <fstream>

using std::ofstream;

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

nu o face. Acestea sunt cazuri rare în care un proces iese brusc. Un proces care se blochează ar putea face ceva similar.