filebuf
dtor and close
on errorSection: 31.10.6.4 [fstream.members] Status: CD1 Submitter: Martin Sebor Opened: 2007-01-20 Last modified: 2016-01-28
Priority: Not Prioritized
View all issues with CD1 status.
Discussion:
basic_filebuf
dtor is specified to have the following
straightforward effects:
Effects: Destroys an object of class
basic_filebuf
. Callsclose()
.
close()
does a lot of potentially complicated processing,
including calling overflow()
to write out the termination
sequence (to bring the output sequence to its initial shift
state). Since any of the functions called during the processing can
throw an exception, what should the effects of an exception be on the
dtor? Should the dtor catch and swallow it or should it propagate it
to the caller? The text doesn't seem to provide any guidance in this
regard other than the general restriction on throwing (but not
propagating) exceptions from destructors of library classes in
16.4.6.13 [res.on.exception.handling].
Further, the last thing close()
is specified to do is
call fclose()
to close the FILE
pointer. The
last sentence of the Effects clause reads:
... If any of the calls to
overflow
orstd::fclose
fails thenclose
fails.
This suggests that close()
might be required to call
fclose()
if and only if none of the calls to
overflow()
fails, and avoid closing the FILE
otherwise. This way, if overflow()
failed to flush out
the data, the caller would have the opportunity to try to flush it
again (perhaps after trying to deal with whatever problem may have
caused the failure), rather than losing it outright.
On the other hand, the function's Postcondition specifies that
is_open() == false
, which suggests that it should call
fclose()
unconditionally. However, since
Postcondition clauses are specified for many functions in the
standard, including constructors where they obviously cannot apply
after an exception, it's not clear whether this Postcondition
clause is intended to apply even after an exception.
It might be worth noting that the traditional behavior (Classic
Iostreams fstream::close()
and C fclose()
)
is to close the FILE
unconditionally, regardless of
errors.
[ See 397 and 418 for related issues. ]
Proposed resolution:
After discussing this on the reflector (see the thread starting with
c++std-lib-17650) we propose that close()
be clarified to
match the traditional behavior, that is to close the FILE
unconditionally, even after errors or exceptions. In addition, we
propose the dtor description be amended so as to explicitly require it
to catch and swallow any exceptions thrown by close()
.
Specifically, we propose to make the following edits in 31.10.3.4 [filebuf.members]:
basic_filebuf<charT,traits>* close();
Effects: If
is_open() == false
, returns a null pointer. If a put area exists, callsoverflow(traits::eof())
to flush characters. If the last virtual member function called on*this
(betweenunderflow
,overflow
,seekoff
, andseekpos
) wasoverflow
then callsa_codecvt.unshift
(possibly several times) to determine a termination sequence, inserts those characters and callsoverflow(traits::eof())
again. Finally, regardless of whether any of the preceding calls fails or throws an exception, the functionitcloses the file ("as if" by callingstd::fclose(file)
).334) If any of the calls made by the functionto, includingoverflow
orstd::fclose
, fails thenclose
fails by returning a null pointer. If one of these calls throws an exception, the exception is caught and rethrown after closing the file.
And to make the following edits in 31.10.3.2 [filebuf.cons].
virtual ~basic_filebuf();
Effects: Destroys an object of class
basic_filebuf<charT,traits>
. Callsclose()
. If an exception occurs during the destruction of the object, including the call toclose()
, the exception is caught but not rethrown (see 16.4.6.13 [res.on.exception.handling]).