85

Possible Duplicate:
Do I need to manually close a ifstream?

Do I need to call fstream.close() or is fstream a proper RAII object that closes the stream on destruction?

I have a local std::ofstream object inside a method. Can I assume that the file is always closed after exiting this method without calling close? I could not find documentation of the destructor.

Community
  • 1
  • 1
Tobias Langner
  • 10,634
  • 6
  • 46
  • 76

3 Answers3

137

I think the previous answers are misleading.

fstream is a proper RAII object, it does close automatically at the end of the scope, and there is absolutely no need whatsoever to call close manually when closing at the end of the scope is sufficient.

In particular, it’s not a “best practice” and it’s not necessary to flush the output.

And while Drakosha is right that calling close gives you the possibility to check the fail bit of the stream, nobody does that, anyway.

In an ideal world, one would simply call stream.exceptions(ios::failbit) beforehand and handle the exception that is thrown in an fstream’s destructor. But unfortunately exceptions in destructors are a broken concept in C++ so that’s not a good idea.

So if you want to check the success of closing a file, do it manually (but only then).

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 7
    I actually check close result every time, because i'm working on an application which must ensure that the data is committed to the disk. Besides, a little out of point, **close does not ensure flush** (on linux at least), and i'm not sure the destructor does flush. I'd actually say it's "best practice" to flush and close, and check erros on both. – Drakosha Jan 26 '11 at 08:57
  • 9
    @Drakosha: ensuring that data is flushed all the way to disk is a whole different thing from what either `flush` or `close` guarantees. The best you can assume in general is that `flush` gets the data out of the process and into the OS level, so e.g. killing the process will not prevent the data being written. There's no portable API to ensure that the data is committed to persistent storage, since the C++ standard has no concept of persistent storage as opposed to other storage presented as (part of) a filesystem. – Steve Jessop Jan 26 '11 at 09:53
  • 2
    I'm also a bit surprised by that linux behavior. The fstream destructor is required to call the `close` member function, `close` is required to close "as if by `fclose`", and `fclose` is defined to flush the stream. So the destructor certainly should flush, although flushing might not necessarily do what you want if there's a risk of the plug being pulled on the machine. You need (non-standard-C++) `fsync` for that. – Steve Jessop Jan 26 '11 at 09:59
  • @Steve Jessop - i'll augment my answer – Drakosha Jan 26 '11 at 10:21
  • I just close everything manually, because it's a habit from Pascal. It does not hurt anyway. – Highstaker May 15 '16 at 09:46
  • 3
    @Highstaker Doing stuff manually in programming that is done automatically is definitely a bad habit. In this particular case it happens to have no ill effect (except for the addition of meaningless lines of code) but it’s not a great principle to adhere to. – Konrad Rudolph May 16 '16 at 09:11
  • "if you want to check the success of closing a file [call `close`]" The problem with that is, it seems like there's not many good options for reporting that error if the paging system quit working; see [this chat transcript](https://chat.stackoverflow.com/rooms/116940/conversation/fstream-close); it looks like the error condition could only be reported on esoteric file systems or something like a serial port maybe (all of which are implementation details from standard C++'s perspective). – jrh Oct 01 '19 at 14:14
  • 1
    @jrh It really depends on the exact failure. If your main storage medium is full then there’s indeed not much the operating system will be able to successfully do. This *can* include failure to write data to any pipe, even when not obviously writing to disk. However, there are other failure modes for `close()`, which might be diagnosable. But *in general*, such failures are fatal and applications can’t handle them easily. – Konrad Rudolph Oct 01 '19 at 14:23
  • 1
    Can you give an example of a failure mode for `close` which is diagnosable? – jrh Oct 01 '19 at 14:32
  • 3
    @jrh Closing a file on an external storage medium after that has been disconnected. This will cause closing (and flushing) to fail, but the application can successfully continue running. – Konrad Rudolph Oct 01 '19 at 14:32
  • 1
    @KonradRudolph you are right, I can reproduce this by pulling out a USB stick on a file that has been written to (but not flushed / closed). Thanks for the suggestion! – jrh Oct 01 '19 at 22:26
  • @KonradRudolph I never knew about this class method `exception` before I read this helpful answer! However, did you mean `stream.exceptions(ios::failbit)` instead of `stream.exception(ios::failbit)`? Ref: https://en.cppreference.com/w/cpp/io/basic_ios/exceptions. – kevinarpe Dec 19 '20 at 09:38
  • 1
    @kevinarpe Yes that was a typo. – Konrad Rudolph Dec 19 '20 at 09:53
8

To append to Amy Lee's answer, it's better to do it manually because this way you can check for errors too.

BTW, according to "close" manpage:

Not checking the return value of close() is a common but nevertheless serious programming error. It is quite possible that errors on a previous write(2) operation are first reported at the final close(). Not checking the return value when closing the file may lead to silent loss of data. This can especially be observed with NFS and with disk quota.

A successful close does not guarantee that the data has been successfully saved to disk, as the kernel defers writes. It is not common for a filesystem to flush the buffers when the stream is closed. If you need to be sure that the data is physically stored use fsync(2). (It will depend on the disk hardware at this point.)

Drakosha
  • 11,925
  • 4
  • 39
  • 52
  • 1
    It's better to do it manually *if* you need to check for errors, this doesn't mean we should *always* close manually. You cannot make a general practice out of an exceptional case. In the general case, when it's closing we don't care how that succeeded, so let it go automatically. – GManNickG Jan 26 '11 at 08:36
  • 4
    @GMan: If you are not checking for errors, this mean you are misleading your user that the data is on the disk while it is not. – Drakosha Jan 26 '11 at 09:00
  • 1
    @Drakisha: But like Steve says, once I close (which is done automatically), error or not it's out of my hands. Also your "augment" is non-standard C++, we're talking about standard `fstream` C++ here. – GManNickG Jan 26 '11 at 17:22
  • 5
    @GMan: it's not really out of your hands, it depends on the context. At least you should let your user know somehow. – Drakosha Jan 26 '11 at 19:49
  • 9
    This is a terrible answer. `close()` is not `fstream::close()`. The latter will always flush, per spec. It's pretty easy to find on the web. – cdunn2001 Jun 17 '13 at 17:02
  • 1
    This answer is wrong. There's no need to close(). Everything here is not correct. – ABCD Dec 19 '17 at 03:38
  • This answer is very valid, the comments are assuming that if the destination drive isn't available a catastrophic system failure has occurred, which isn't true for cases like writing to a network drive or a USB stick; if your program allows users to select a save location, please close manually and report errors! It's not "hopeless", you could e.g., tell the user that the file save failed and save the file somewhere else. – jrh Oct 04 '19 at 13:24
  • @cdunn2001 Even though `fstream::close()` is not `close()`, and the spec says the destructor will always flush, that doesn't mean the spec says that a removeable or unreliable drive hasn't had a problem that prevents the flush from succeeding. This isn't a terrible answer. If I were using a program that saved crucial data to a network drive and it failed to inform me that the save failed and I lost hours of work due to connection loss, I would not feel much better knowing that "at least the programmer's code used good RAII style". – jrh Oct 04 '19 at 13:29
  • 1
    @jrh, You're making a reasonable distinction. You want to be certain that the return value of the underlying system call was actually checked. Yes, that's important. So I went to [the source code](https://github.com/gcc-mirror/gcc/blob/16e2427f50c208dfe07d07f18009969502c25dc8/libstdc%2B%2B-v3/config/io/basic_file_stdio.cc#L298). The answer is "yes"; in fact the return value of `fclose()` is checked, and a failure is effectively popped up the call-stack and turned into a stream failure at the appropriate location. So `fstream::close()` is perfectly safe! – cdunn2001 Jul 10 '21 at 18:26
1

I think it's a good practice to close your fstream, cause you need to flush the buffer, that what i've been told

Amy Lee
  • 277
  • 3
  • 15
  • 5
    if fstream is a RAII object, it will be closed and thus the buffers flushed anyway. The main question is whether I need error handling on all control flows to ensure that it is flushed. – Tobias Langner Jan 26 '11 at 08:31
  • 4
    Sorry, -1 only because it somehow had +2. Manually releasing a resource is either a sign of bad programming, or a misunderstanding of the purpose of a container. – GManNickG Jan 26 '11 at 08:34
  • 1
    @GMan: I would argue that not caring if your file closed properly is the exceptional case, and you should call `close()` yourself in most situations. *Far* too many software developers make assumptions that I'd rather they didn't about the reliability and availability of user filesystems. – Nick Bastin Jan 26 '11 at 22:51
  • @GManNickG See [my comment](https://stackoverflow.com/questions/4802494/do-i-need-to-close-a-stdfstream/4802556#comment102846164_4802527) on the other answer; any program that has the option to write to media that is possibly unreliable or removable (e.g., flash drives, network drives) really should manually close, so that you can inform the user that the save failed and/or let them pick a different location. – jrh Oct 04 '19 at 12:45