On Thursday, 31 January 2013 at 23:53:26 UTC, Steven
Schveighoffer wrote:
A destructor should ONLY be used to free up resources other
than GC allocated memory. Because of that, it's generally not
used.
It should be used almost as a "last resort".
For example, a class that holds a file descriptor should have
both a destructor (which closes the descriptor) and a manual
close method. The former is to clean up the file descriptor in
case nobody thought to close it manually before all references
were gone, and the latter is because file descriptors are not
really managed by the GC, and so should be cleaned up when they
are no longer used.
This kind of gives us a paradox, since the class is managed via
the GC, how do you know it's no longer used (that is, how do
you know this is the last reference to it)? That is really up
to the application design. But I wouldn't recommend relying on
the GC to clean up your descriptors.
-Steve
I've actually run into this very issue: I was iterating on files,
opening them, and placing the descriptor in GC-allocated RAII
data. I can't remember if class or struct, but not a big issue.
Come to think about it, I think I was using "File", but
allocating them because I thought they were classes `auto f = new
File("my file", "r")`.
After running for a second, my program halts, because an
exception was thrown trying to open a new file:
"Cannot open file: Too many open file handles".
It was basically: Sure, the GC will destroy and close files for
you... if you forget... eventually...
I ended up closing them in scope(exit) blocks. Problem
immediately solved. Or I could have stopped allocating my File's
on the heap.
Either way, it shows you shouldn't rely on the GC for
deterministic destruction.