255

Do I need to manually call close() when I use a std::ifstream?

For example, in the code:

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

Do I need to call file.close() manually? Shouldn't ifstream make use of RAII for closing files?

Jamal
  • 763
  • 7
  • 22
  • 32
Gustavo Muenz
  • 9,278
  • 7
  • 40
  • 42

4 Answers4

305

NO

This is what RAII is for, let the destructor do its job. There is no harm in closing it manually, but it's not the C++ way, it's programming in C with classes.

If you want to close the file before the end of a function you can always use a nested scope.

In the standard (27.8.1.5 Class template basic_ifstream), ifstream is to be implemented with a basic_filebuf member holding the actual file handle. It is held as a member so that when an ifstream object destructs, it also calls the destructor on basic_filebuf. And from the standard (27.8.1.2), that destructor closes the file:

virtual ˜basic_filebuf();

Effects: Destroys an object of class basic_filebuf<charT,traits>. Calls close().

Community
  • 1
  • 1
Eclipse
  • 44,851
  • 20
  • 112
  • 171
  • 7
    +1 I didn't know that RAII handles that...I guess you learn something new everyday – TStamper Apr 14 '09 at 15:21
  • 37
    Using a nested scope just to close the file is completely artificial - if you mean to close it, call close() on it. –  Apr 14 '09 at 15:23
  • @Neil - good point, it's a habit I've picked up from using a lock library that doesn't have a non-destructor release method. If there's a function that lets you close it, go ahead and use it. – Eclipse Apr 14 '09 at 15:25
  • 4
    Although, you might be able to argue that restricting the object's lifetime to the necessary scope means that you won't accidentally access a closed ifstream. But that's a bit contrived. – Eclipse Apr 14 '09 at 15:26
  • 4
    I'm all for limiting scope as much as possible :-) –  Apr 14 '09 at 15:29
  • I am all for limiting scope, but adding an unnecessary nested scope is asking for trouble. So maintainer (other than you) may incorrectly see it as unnecessary and remove it thus keeping your file open longer than necessary. Maybe a helper function to restrict scope would be more appropriate? – Martin York Apr 14 '09 at 15:50
  • Why an unnecessary scope? Just let the ifstream live in the scope it needs to live to get the job done, and it will be closed just in time - no sooner or later than necessary. – Nemanja Trifunovic Apr 14 '09 at 16:36
  • 2
    Also, note that basic_filebuf::close() will always flush. Just rely on RAII. Don't let unanticipated exceptions alter your code. – cdunn2001 Jun 17 '13 at 17:04
  • 12
    In C++ nested scopes are almost never unnecessary. They have everything to do with the behavior of the code, especially when something throws. If a future maintainer removes them, he doesn't know C++ very well. – Elliot Cameron Nov 14 '13 at 22:39
  • 4
    Sometimes you do need to call `close()` manually for error handling. – ks1322 Aug 07 '16 at 11:37
  • 1
    I had a bad experience.The destructor don't close the C stream if calling the constructor with c-style FILE* of std::ifstream in VS2013. `virtual __CLR_OR_THIS_CALL ~basic_filebuf() _NOEXCEPT { // destroy the object if (_Myfile != 0) _Reset_back(); // revert from _Mychar buffer if (_Closef) close(); }` – samm Oct 21 '16 at 10:03
  • 3
    @ssfang (hope you don't mind such a late comment): 1.: This constructor is not [standard](http://en.cppreference.com/w/cpp/io/basic_ifstream/basic_ifstream), so must be a MSVC extension. 2.: This behaviour can be considered natural: Stream closes what it opened itself and does not close what it did not open itself... – Aconcagua Jul 19 '17 at 09:41
  • 1
    I totally agree with not calling close() because we should not do manual cleaning up and fstream uses RAII. BUT since the discussion seems one-sided I just wanted to point out this tutorial says otherwise: https://www.cplusplus.com/doc/tutorial/files/ "When we are finished with our input and output operations on a file we shall close it so that the operating system is notified and its resources become available again. For that, we call the stream's member function close. " – ClarHandsome Sep 01 '20 at 02:22
  • 1
    RAII is great but I don't think it outweighs the benefits of having an error message if, e.g., the write failed due to a USB stick being pulled out. – jrh Sep 12 '20 at 13:58
82

Do you need to close the file?
NO

Should you close the file?
Depends.

Do you care about the possible error conditions that could occur if the file fails to close correctly? Remember that close calls setstate(failbit) if it fails. The destructor will call close() for you automatically because of RAII but will not leave you a way of testing the fail bit as the object no longer exists.

Martin York
  • 257,169
  • 86
  • 333
  • 562
  • I think it's worth mentioning that you can use the `exceptions` function to turn such an error into an exception throw instead of doing a manual test. There's [an interesting blog post by Eric Lippert](https://ericlippert.com/2008/09/10/vexing-exceptions/) which makes a good case for file IO being an example of a situation where exceptions are truly the better option because of their inherant asynchrony. I.e. a mounted disk count be removed at _any_ time, not just when your program checks it's there. – Pharap Sep 27 '22 at 10:38
7

You can allow the destructor to do it's job. But just like any RAII object there may be times that calling close manually can make a difference. For example:

#include <fstream>

using std::ofstream;

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

writes file contents. But:

#include <stdlib.h>

#include <fstream>

using std::ofstream;

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

doesn't. These are rare cases where a process suddenly exits. A crashing process could do similar.

ericcurtin
  • 1,499
  • 17
  • 20
6

No, this is done automatically by the ifstream destructor. The only reason you should call it manually, is because the fstream instance has a big scope, for example if it is a member variable of a long living class instance.

Dimitri C.
  • 21,861
  • 21
  • 85
  • 101
  • 5
    Another reason might be to check file-closing errors and to prevent throwing destructor, if exceptions are allowed with the stream. – Daniel Langr Jul 19 '17 at 09:13