2009-04-14 11 views
138

Czy muszę ręcznie dzwonić pod numer close(), gdy używam numeru std::ifstream?Czy muszę ręcznie zamknąć 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ę zadzwonić file.close() ręcznie? Czy nie powinno być ifstream używać do zamykania plików RAII?

Odpowiedz

182

NO

To, co jest dla RAII, niech destructor wykonywać swoje zadania. Nie ma nic złego w ręcznym zamykaniu go, ale nie jest to metoda C++, to programowanie w C z klasami.

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

W standardzie (27.8.1.5 Szablon klasy basic_ifstream), ifstream ma zostać zaimplementowany z elementem basic_filebuf z rzeczywistym uchwytem pliku. Jest przechowywany jako element, więc gdy obiekt typu ifstream ulega zniszczeniu, wywołuje on również destruktor pod numerem basic_filebuf. I od normy (27.8.1.2), to destruktor zamyka plik:

virtual ˜basic_filebuf();

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

+12

+1 - Przynajmniej jedno, kto wie, co oznacza RAII :-) – Milan

+3

+1 Nie wiedziałem, że RAII to obsługuje ... Domyślam się, że codziennie się uczysz nowego – TStamper

+13

Używanie zagnieżdżonego zakresu tylko do zamknięcia pliku całkowicie sztuczny - jeśli chcesz go zamknąć, wywołaj close() na nim. –

43

Czy chcesz zamknąć plik?
NIE

Czy należy zamknąć plik?
Zależy.

Czy interesują Cię możliwe warunki błędu, które mogą wystąpić, jeśli plik nie zostanie poprawnie zamknięty? Pamiętaj, że bliskie połączenia setstate (failbit), jeśli się nie powiedzie. Destruktor wywoła automatycznie funkcję close() z powodu: RAII, ale nie pozostawi ci możliwości testowania bitu błędu, ponieważ obiekt już nie istnieje.

4

Nie, jest to wykonywane automatycznie przez destruktor ifstream. Jedynym powodem, dla którego powinieneś wywołać to ręcznie, jest to, że instancja fstream ma duży zakres, na przykład jeśli jest to zmienna składowa długiej instancji klasy żywej.

+0

Innym powodem może być sprawdzanie błędów zamykania pliku i zapobieganie wyrzucaniu destruktora, jeśli są dozwolone wyjątki ze strumieniem. –

8

Zgadzam się z @Martin. Jeśli napiszesz do pliku, dane mogą nadal znajdować się w buforze i mogą nie zostać zapisane w pliku do czasu wywołania close(). Nie robiąc tego ręcznie, nie masz pojęcia, czy wystąpił błąd, czy nie. Brak zgłaszania błędów użytkownikom jest bardzo złą praktyką.