Bug 1250 – std.stream.BufferedFile should have a destructor with close()
Status
RESOLVED
Resolution
INVALID
Severity
normal
Priority
P2
Component
phobos
Product
D
Version
D1 (retired)
Platform
x86
OS
All
Creation time
2007-05-28T03:46:00Z
Last change time
2014-02-16T15:25:23Z
Assigned to
bugzilla
Creator
wbaxter
Comments
Comment #0 by wbaxter — 2007-05-28T03:46:52Z
std.stream.BufferedFile should have a destructor that calls close().
std.stream.File has one, but std.stream.BufferedFile does not.
It means not all the data will get written to disk with the usage pattern:
{
scope f = new BufferedFile(filename,FileMode.Out);
// do a bunch of writes
// hope f gets closed by RAII magic (it won't)
}
Comment #1 by fvbommel — 2007-05-28T05:19:11Z
You can't do that; it causes undefined behavior if BufferedFile is collected by the GC. BufferedFile internally uses a File, and GC-collected objects can't safely reference other GC-able objects in their destructors since they may have been collected earlier and accessing deleted objects is Bad(TM).
File can call close() in the destructor because it doesn't need to access GC-able objects to close(), it just performs the needed OS calls directly.
The only way to safely put a close() in the destructor of BufferedFile (or BufferedStream, its superclass) would be to make it a "scope" class to require deterministic destruction, but that would disallow a lot of use cases.
You can add a "scope(exit) f.close();" after the declaration of f to safely get the closing behavior you want.
Comment #2 by wbaxter — 2007-05-28T13:48:32Z
(In reply to comment #1)
> You can't do that; it causes undefined behavior if BufferedFile is collected by
> the GC. BufferedFile internally uses a File, and GC-collected objects can't
> safely reference other GC-able objects in their destructors since they may have
> been collected earlier and accessing deleted objects is Bad(TM).
> File can call close() in the destructor because it doesn't need to access
> GC-able objects to close(), it just performs the needed OS calls directly.
Ouch. That kinda defeats one of the major purposes of having 'scope' in the first place. Sounds like D needs that "scope destruction" flag passed to the destructor as has been suggested before, so that people have a way to make their classes work optimally with scope.
> The only way to safely put a close() in the destructor of BufferedFile (or
> BufferedStream, its superclass) would be to make it a "scope" class to require
> deterministic destruction, but that would disallow a lot of use cases.
...which is basically always the case. No one wants to slap a 'scope' on a class because it just limits the possibilities. I guess you could derive a ScopeBufferedFile from BufferedFile and make that a scope class.
scope ScopeBufferedFile : BufferedFile {
~this() { m_file.close(); }
}
Seems kind of inelegant, though.