Czy muszę ręcznie zamykać ifstream?


201

Czy muszę ręcznie dzwonić, close()gdy używamstd::ifstream ?

Na przykład w kodzie:

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

Czy muszę dzwonić file.close()ręcznie? Czy nie należy ifstreamużywać RAII do zamykania plików?

Odpowiedzi:


251

NIE

Po to jest RAII, niech destruktor wykona swoją pracę. Ręczne zamykanie nie szkodzi, ale to nie jest sposób w C ++, programuje się w C z klasami.

Jeśli chcesz zamknąć plik przed końcem funkcji, zawsze możesz użyć zagnieżdżonego zakresu.

W standardzie (27.8.1.5 Szablon klasy basic_ifstream) ifstreamnależy zaimplementować basic_filebufelement posiadający rzeczywisty uchwyt pliku. Jest on utrzymywany jako element członkowski, więc gdy obiekt ifstream ulega zniszczeniu, wywołuje również destruktor basic_filebuf. I ze standardu (27.8.1.2) ten destruktor zamyka plik:

virtual ˜basic_filebuf();

Efekty: Niszczy obiekt klasy basic_filebuf<charT,traits>. Połączenia close().


4
+1 Nie wiedziałem, że RAII radzi sobie z tym ... Myślę, że uczysz się czegoś nowego
— każdego dnia

21
Używanie zagnieżdżonego zakresu tylko do zamykania pliku jest całkowicie sztuczne - jeśli chcesz go zamknąć, wywołaj na nim close ().

3
Chociaż możesz argumentować, że ograniczenie czasu życia obiektu do niezbędnego zakresu oznacza, że ​​przypadkowo nie uzyskasz dostępu do zamkniętego strumienia ifstream. Ale to trochę wymyślone.
— Zaćmienie

9
W C ++ zagnieżdżone zakresy prawie nigdy nie są niepotrzebne. Mają wszystko do czynienia z zachowaniem kodu, zwłaszcza gdy coś się rzuca. Jeśli przyszły opiekun je usunie, nie zna dobrze C ++.
— Elliot Cameron

2
Czasami musisz zadzwonić close()ręcznie w celu obsługi błędów.
— ks1322,

71

Czy musisz zamknąć plik?
NIE

Czy powinieneś zamknąć plik?
Zależy.

Czy zależy Ci na możliwych warunkach błędu, które mogą wystąpić, jeśli plik nie zostanie poprawnie zamknięty? Pamiętaj o zamkniętych połączeniach, setstate(failbit)jeśli się nie powiedzie. Destruktor zadzwoni close()do ciebie automatycznie z powodu RAII, ale nie pozostawi Ci możliwości przetestowania bitu niepowodzenia, ponieważ obiekt już nie istnieje.


14

Zgadzam się z @Martin. Jeśli piszesz do pliku, dane mogą nadal znajdować się w buforze i mogą nie zostać zapisane do pliku, dopóki nie close()zostanie wywołane. Bez zrobienia tego ręcznie nie masz pojęcia, czy wystąpił błąd, czy nie. Niezgłaszanie błędów użytkownikowi jest bardzo złą praktyką.


5

Nie, robi to automatycznie ifstreamdestruktor. Jedynym powodem, dla którego powinieneś wywołać go ręcznie, jest to, że fstreaminstancja ma duży zasięg, na przykład, jeśli jest zmienną składową instancji klasy długo żyjącej.


4
Innym powodem może być sprawdzenie błędów zamykania plików i zapobieganie rzucaniu destruktora, jeśli ze strumieniem dozwolone są wyjątki.
— Daniel Langr,

4

Możesz pozwolić destruktorowi wykonać swoją pracę. Ale podobnie jak każdy obiekt RAII może się zdarzyć, że ręczne wywołanie metody close może mieć znaczenie. Na przykład:

#include <fstream>

using std::ofstream;

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

zapisuje zawartość pliku. Ale:

#include <stdlib.h>

#include <fstream>

using std::ofstream;

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

nie. Są to rzadkie przypadki, gdy proces nagle kończy się. Awaria procesu może zrobić podobnie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.