CppCon 2019: Ben Saks “Back to Basics: Exception Handling and Exception Safety”
Vložit
- čas přidán 16. 06. 2024
- CppCon.org
-
Discussion & Comments: / cpp
-
Presentation Slides, PDFs, Source Code and other presenter materials are available at: github.com/CppCon/CppCon2019
-
Exception handling (EH) is a powerful tool for dealing with errors. Using EH effectively can produce code that is simpler, more readable, and more robust than you can get with alternative mechanisms. In this session, we will explain the purpose of EH by contrasting it with the most common alternative, function return codes. We will show you the preferred techniques for throwing and catching exceptions, including which types of objects to throw, when to throw them, and how to catch them. We will describe the different levels of exception safety guarantees and demonstrate techniques like RAII that will help you write functions that provide those guarantees. We will illustrate how to write exception-neutral code that allows you to use EH without creating additional failure points.
-
Ben Saks
Chief Engineer, Saks & Associates
-
Videos Filmed & Edited by Bash Films: www.BashFilms.com
*-----*
Register Now For CppCon 2022: cppcon.org/registration/
*-----*
Thanks Ben. some complementary comments for future seekers: destructors are being called in reverse order cause local variables are in stack here. build-in types don’t throw cause they come from C which doesn’t have EH.
Thanks for a great informative talk! Covering not only how exceptions work and propagate but also a crash course in how to write code with exceptions in under an hour is not a easy task, but Ben made it look easy.
Thank you for this insightful point of view of things!
The best talk on exception handling!
Loud and clear, thanks, bro!
Amazing talk!
Amazing talk! thanks for this
Doesn't the logic for making swap nothrow also apply to move constructors?
25:03 will watch later
This us great 😊😊😊😊
Thank you! 😊
Did anyone find slides in the github ?
the problem with classic example of RAII and C++ 31:30 is destructor noexcept /~file() noexcept;// reason for which is 42:20 /
is that writes almost always buffered and error for write may be reported in fclose.
so destructor should somehow report error of fclose, and that part makes whole example stupid.
" The fclose() function shall fail if:
[EAGAIN]
[CX] [Option Start] The O_NONBLOCK flag is set for the file descriptor underlying stream and the thread would be delayed in the write operation. [Option End]
[EBADF]
[CX] [Option Start] The file descriptor underlying stream is not valid. [Option End]
[EFBIG]
[CX] [Option Start] An attempt was made to write a file that exceeds the maximum file size. [Option End]
[EFBIG]
[XSI] [Option Start] An attempt was made to write a file that exceeds the process' file size limit. [Option End]
[EFBIG]
[CX] [Option Start] The file is a regular file and an attempt was made to write at or beyond the offset maximum associated with the corresponding stream. [Option End]
[EINTR]
[CX] [Option Start] The fclose() function was interrupted by a signal. [Option End]
[EIO]
[CX] [Option Start] The process is a member of a background process group attempting to write to its controlling terminal, TOSTOP is set, the process is neither ignoring nor blocking SIGTTOU, and the process group of the process is orphaned. This error may also be returned under implementation-defined conditions. [Option End]
[ENOSPC]
[CX] [Option Start] There was no free space remaining on the device containing the file. [Option End]
[EPIPE]
[CX] [Option Start] An attempt is made to write to a pipe or FIFO that is not open for reading by any process. A SIGPIPE signal shall also be sent to the thread. [Option End]
The fclose() function may fail if:
[ENXIO]
[CX] [Option Start] A request was made of a nonexistent device, or the request was outside the capabilities of the device.
"
It is not like it would be possible to do anything other than report the error in any case; whether fclose succeeded or failed, the stream is dissociated with the underlying file and using the stream again is undefined behavior. That makes a better case for using fflush+fsync after the last write so you can handle any errors.
Or better yet, not use the C file API unless you are forced to.
@@flamewingsonic whole video is about how to correctly report errors with exceptions, and actual example shows that or RAII is not possible for output file (most of output files do flush when close - that's just how buffering works and manual call for fflush/fsync/fclose is not RAII) or exception is not possible (you actually can register call back for such error in constructor and call it in destructor but that will not be exception)
so my preference is not use RAII for work - only use it for check, and if file still opened at destructor start, when class should close file (ignoring any error) delete it, and if possible report logic error in some (application/system) log, in case of network streams call back is preferable (as you can't delete already sent data).
@@zdnui45jbsodfteu66 Does a similar problem exist in ofstream etc?
Would the local variable and swap idiom construct the object twice or does the compiler optimize those away?
It constructs a second object in any case not just to enforce the strong guarantee (if construction of the temporary object fails and throws an exception, the member object is left alone), but also to fulfill std::swap's contract that the type to be swapped has to be move-assignable and move-constructible, which essentially requires that it's a lvalue. Nobody keeps you from writing a swap method that also takes a rvalue reference, but in the end that would be a move assignment operator under a different name.
Q.e.d. 😂 ❤❤