8 ms·
One thing that surprised me a bit was that exceptions are more or less recommended in these guidelines. In the section "4.18 Exception handling", it is mentione
by vodou 3y ago
One thing that surprised me a bit was that exceptions are more or less recommended in these guidelines. In the section "4.18 Exception handling", it is mentioned that "most compilers provide options (such as -fno-exceptions) that can be used to disable exceptions in order to eliminate the code and size overheads". Then it goes on describing how this makes it impossible to comply with a bunch of other rules.
Since these are "guidelines for the use of C++17 in critical systems", I would have expected it to prohibit exceptions due to their non-determinstic nature. On a side note, dynamic memory is prohibited (rule 21.6.1).
I haven't read the earlier MISRA C++ guidelines so I don't know if this have changed.
- otabdeveloper4 3y agoProhibiting exceptions is a toxic antipattern. Once you have more than one thread you want to propagate fatal errors in a sane way. ("Just crash the whole program, #yolo" is not a sane way.)
- shadowgovt 3y agoIt depends on the problem domain. For automotive embedded software? Definitely not. But Google, for instance, bans them in much of its server code under the principle that exceptions should denote circumstances where the entire program cannot recover and when a server node cannot recover, logging noisily and failing fast so that it can be restarted into a working state is preferable to trying to unwind a bad state. Given that constraint, they conclude that the overhead of maintaining exception unwinding and the non-local control flow aren't worth it.
- cpgxiii 3y agoThe classic GSG prohibition on exceptions has more to do with a lack of exception safety in their legacy code base than anything else. Promptly-crash-on-failure can be achieved by adopting a "don't catch exceptions" style, with significant advantages of not throwing away much of the strengths of RAII or needing the evil hack that is two-phase initialization.
- shadowgovt 3y agoYou can for all intents and purposes avoid two phase init with factory functions (which is how Go does it) and private constructors. (To my memory though, Google didn't throw away the benefits of RAII without allowing exceptions... They discouraged complicated behavior in constructors and so the only thing a constructor could fail on was OME, which was supposed to crash anyway).
- otabdeveloper4 3y agoAll Google code is a huge antipattern and an example of enterprise coding gone insane.
- GuB-42 3y ago"just crash the whole program" is much more sane than to attempt to handle unrecoverable errors. Almost all systems to which MISRA apply have watchdogs, and crashing to let the watchdog restart the program is a common pattern.
- AlotOfReading 3y agoThere are cases in MISRA's problem domain where the software watchdog is part of the same program, and fully crashing that program is a different, more severe error than alternatives.
- Espressosaurus 3y agoProhibiting exceptions is necessary in the embedded space for, err, space and allocation reasons. Just crash the system and reboot the MCU can make sense depending on the application. And where it can't, you need to take the same kind of care for handling every single problem at the call site, or correctly propagating it to a layer that can handle it. Exceptions aren't special here, they are simply a way to do error handling and recovery. It's the kind of rule that doesn't make sense for applications, but when you've got tightly constrained memory limits, it makes sense.
- mgaunard 3y agoExceptions don't generate more space outside of code where you use try/catch, which is generally viewed as an anti-pattern.
- vodou 3y agoI have personally removed exceptions (to be fair, it was only few) from an embedded application and introduced the -fno-exceptions flag. The binary size was reduced by ~20%, which can be important if you are doing SW updates to space and have a link budget... Also, the reduced code size is more cache friendly on a system with rather limited cache memories.
- mgaunard 3y agoWell the problem was most likely with the code then, not the language feature -- because the changes are quite localized to throw sites and catch sites, not throughout the code.
- jandrewrogers 3y agoExceptions are not a sane way to handle many error conditions either. Predictably and efficiently handling fatal error conditions will require custom handling code regardless. For many types of software, the downsides of exceptions are not offset by a corresponding benefit in real reliable systems. I’ve worked on systems that work both ways and I have a hard time recommending exception use.
- mmoll 3y agoOn the other hand, once your embedded system is sufficiently large, people will want to use (and inevitably will use at some point) standard containers such as std::string or std::vector. And without exceptions, all of those might invoke UB at any time (I have yet to see a standard library that understands and honors -fno-exceptions; usually they just drop all try-catch blocks and all throws)
- TwentyPosts 3y agoCould you elaborate on that? I'd love to see an example of this. Are you saying that even relatively simple code (using eg. std::vector) could easily cause UB if -fno-exceptions is enabled?
- accelbred 3y agoAny exception thrown with -fno-exceptions results in std::terminate. The behavior of std::terminate is unspecified.
- Karellen 3y agoThe behaviour is unspecified by the standard. Your compiler vendor has to pick a (reasonable) behaviour though and apply it consistently, and while they are not required to document it (IIRC - I think that's just for implementation-defined?) you can probably get them to tell you if you have a good support relationship with them. Or you can just figure out what the compiler does, and hope they don't change the behaviour too much with the next release :-)
- nextaccountic 3y agoC++23 has std::expected, right?
- captainmuon 3y agoExceptions are not non-deterministic, although the control flow can be a bit non obvious of course. I think if you disallow exceptions you run into other problems. How can a constructor fail now? You need to have some kind of flag showing if an object is fully constructed. But then that goes against the idea to "make illegal states unrepresentable". I do wish C++ had more tools to reign in exceptions. Maybe an "onlythrows X" annotation that says only these very specific exceptions may escape from a block, and the checker will complain if it cannot prove that only X can be thrown. The opposite of checked exceptions basically.
- jupp0r 3y agoThe constructor error problem is easily solved by using factory functions and two phase construction. The problem is that the standard library is relying on exceptions quite a bit and major parts become unusable.
- lelanthran 3y agoFor what definition of "easy"? Simply passing by value can result in a constructor that fails, while still bypassing any of the factory functions.
- jupp0r 3y agoEasy as in "competent C++ programmers do this every day"? If the copy constructor can fail and you don't want that, then delete it?
- lelanthran 3y ago> If the copy constructor can fail and you don't want that, then delete it? You're trivialising just how deeply embedded exceptions are into the design of the language. I gave just one example and it was not meant to be exhaustive, just one 'gotcha' that you won't find out till runtime and your program starts (worst case) giving you slightly incorrect results without you knowing about it... So, yeah, if you want to do without exceptions (without having your program execute random code) you need to know in advance what special cases to handle, like unintended copy construction, or failures in overloaded operators, or which std libs can be used and which cannot, or which C++ libraries can be linked, and which cannot. All of which is perfectly possible, but taken together is hardly "easy". It's tedious, error-prone, bloated ... but hardly what someone would call "easy".