3 ms·
I'm not sure I understand what you mean. For your "release resources" point: fclose() can fail, yet in fstream::~fstream() that must be ignored. So that's not
by lomnakkus 9y ago
I'm not sure I understand what you mean.
For your "release resources" point: fclose() can fail, yet in fstream::~fstream() that must be ignored. So that's not great.
For your "execute after prior operations in LIFO manner" point... what is the purpose except to clean up resources? If it isn't about scoped resources, then what is it about, given that defer(...) is explicitly about scope? I mean, if "defer" wasn't about that, we'd just write a few more statements doing the thing and not bother with the whole defer(...) thing?!?
- mehrdadn 9y ago> For your "release resources" point: fclose() can fail, yet in fstream::~fstream() that must be ignored. So that's not great. No, fclose() cannot fail to close the file. The return code merely tells you whether any pending write operations have failed in the meantime, which is unrelated to the releasing of the FILE. The FILE will be closed either way. The C standard is explicit about this: Whether or not the call succeeds, the stream is disassociated from the file and any buffer set by the setbuf or setvbuf function is disassociated from the stream (and deallocated if it was automatically allocated). http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#page=282 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#pa... > For your "execute after prior operations in LIFO manner" point... what is the purpose except to clean up resources? Well, fflush() is an easy example. Or, any logging that must occur at the end of a function call regardless of its success or failure. Or, really, anything else that isn't releasing a resource...
- lomnakkus 9y agoHang on, isn't fclose() tasked with flushing buffered I/O, or are we assuming entirely synchronous I/O? Well, I suppose fsync() absolves POSIX of that, but in practice? fstream::~fstream() has to flush the IO (at least at runtime library level) and if that fails? > The FILE will be closed either way. That doesn't matter. It only matters in a resource-accounting way -- the resource will be freed, but that program does the wrong thing (partial write, 50-50 whether write happens, whatever). > > For your "execute after prior operations in LIFO manner" point... what is the purpose except to clean up resources? > Well, fflush() is an easy example. Or, logging that must occur at the end of a function call regardless of its success or failure. Or, really, anything else that isn't releasing a resource... fflush() can also fail (see above). Logging can also fail, disastrously, if it's going through a serial port -- though, it technically doesn't necessarily break the program's semantic meaning -- nobody wants to wait for N hours for the next log statement to be sent before continuing on with the program's execution. Do you see, now, what I mean? (EDIT: I think HN screwed up the quoting on my reply, but I think I've fixed it. Please yell if I quoted you or me(!) badly.)
- mehrdadn 9y ago> Hang on, isn't fclose() tasked with flushing buffered I/O You're not reading carefully. I never said fclose() flushes anything. Please go back and read what I wrote. >> The FILE will be closed either way. > That doesn't matter. It only matters in a resource-accounting way. The resource will be freed, but that program does the wrong thing (partial write, 50-50 whether write happens, whatever). fflush() can also fail. Logging can also fail, disastrously [...] Yes, you are only confirming what I wrote. Again, please go back and read what I wrote; it seems you are not reading carefully and are very confused what I have been saying (and what you yourself were asking). Here, I'll quote myself again. I said: "Destructors are meant to release resources, whereas finally/scope(exit) are meant to execute after prior operations in a LIFO manner." You were surprised these are distinct categories and wanted examples of the operations that would need to occur in a LIFO order but which are not releasing any resources. I cited flushing and logging as easy examples of such operations. You then proceeded to object that fflush and logging can... fail? Yes, I agree; of course they can -- indeed that was half of my entire point as to why they are inappropriate for destructors/RAII, but appropriate for finally/scope(exit). To repeat even more explicitly: both flushing and logging would need to occur in finally{} blocks, as they are not releasing any resources. In addition, neither of them is appropriate for a destructor, because these operations can fail, and destructors cannot propagate the corresponding exceptions. By contrast, closing a file needs to occur in a destructor, because is releasing a resource (which inherently cannot fail). And indeed, this implies fclose() would need to be called in a destructor and have its return value ignored, as it always succeeds in closing the file.
- lomnakkus 9y ago> You're not reading carefully. I never said fclose() flushes anything. Please go back and read what I wrote. I did read, thanks. AFAICT, the POSIX standard mandates that fclose() must flush pending output, so what you said is immaterial. That is, it can fail to flush in exactly the way I mentioned, and so any destructor-like behavior is faced with a decision as to "what to do". Now, you're technically right in that the RESOURCE representing the file will be closed, but my counter-point was that it doesn't matter. Either the destructor swallows the error yielding silent incorrect behavior, or the destructor must throw and abort the program. Neither is very helpful, though I guess aborting the program doesn't play havoc with the program's meaning. My question is really: What does scope(exit) actually do if a fflush() fails, for example? Any non-built-in equivalent of "scope(exit)" in C++ would have to use a destructor to function reliably, I think, so what to do? Does it throw? When does it throw? Is it allowed to throw if we're already unwinding the stack due to another exception? This is horribly complicated... and that's my overall point, really. Just the fact that a resource was technically freed is moot if the program does the wrong thing. The horrible complicatedness of all of this is an indicator that something is deeply wrong. (Incidentally, in Java the try-with-resources statement actually seems to do at least a semi-sane thing which is that an exception during a "finally" clause attaches that exception to the already "active" exception in case it happens during unwinding from a thrown exception. Or the other way around, can't be arsed to look it up. The point is that unwinding happens, but errors are not lost. I'm not sure if it actually does the right thing wrt. file descriptors, but one hopes so.)