When noexcept?
blog.quasardb.net
blog.quasardb.net
If the type has a move constructor that is noexcept, then each element can be move-constructed without fear of an exception occurring. For many types, this is vastly more efficient.
* Code that will never throw an exception
* Code where throwing an unanticipated and therefore uncaught exception should trigger a failfast and crashing is not only the right behavior but the desired behavior. This should be the rarest of cases, but it does happen.
* Code that is called across an ABI boundary that it is not safe for an exception to cross. This is the most common case as OS callbacks fit this. This should be noexcept because having the exception propagate across exception unaware code causes bad things to happen, it's also undefined behavior to boot.
I don't care what gets thrown, because it's in the end going to be an std::exception (this is the part that Java messed up)
I do care if a function will throw, because it radically changes its behavior.
The problem I want to avoid is a silly function such as stoi throwing and having the exception propagated up to main, after which the whole program (orderly) shuts down. Right now this can be avoided only with careful exception design and making sure all exception "escape points" to C functions, message loops, etc are covered.
Swift I think is one of the few languages supporting this.
Object layouts will be likely different and the main program will probably crash.
The breakage from mixing different library versions (say, MSVCRT versions, for example) is a direct result of violating the ODR.
Make sure that your compiler provides a stable std library ABI.
Is this done a lot in practice? I had the impression that a lot of projects stick to C APIs in dynamic libraries.
In practice the reason that many projects provide a C ABI is that they want to interoperate with other languages and the C ABI, being extremely minimalist, is the least common denominator.
I don't understand: std::exception is entirely optional (and I, for example, never use it: I always build my own exception hierarchy; but, even though I write my native code almost exclusively in C++, I believe it is absolutely incorrect to expose a C++ API from a library, so you'd never know or care) while in Java you absolutely have to implement Throwable and Exception is actually designed well enough that most people (not me, of course ;P) generally use it... I mean, in C++ you literally can just throw a "const char *" and catch that.
The important thing with exceptions in C++ is having a root class. I use std::exceptions, others are also ok as long as they are used consistently. If the goal is to trap everything, like in a library even ... is ok.
The big difficulty lies in isolating certain kinds of exceptions to components. Some are recoverable, others should lead to termination, some should interrupt the current operation, others should trigger a retry. The type system offers no support with that.
Verification of noexcept would be a start, as it allows some rudimentary marking of boundaries.
I will say that I didn't provide an argument for not using std::exception, nor was I trying to convince someone else not to do so; I was simply stating that C++ does not require it and a lot of code doesn't use it: it sounded like the person I was responding to was claiming that in C++ you knew everything was eventually std::exception while that wasn't the case for Java, when the exact opposite is actually true (that in C++ you can and often do run into cases where an exception is just some random data type, and in Java all exceptions fundamentally must implement Throwable as an engine constraint). I only used the fact that I don't use it as an example of someone who doesn't. FWIW, I actually use a lot of my code in environments where I can't use the standard library, so even your paragraph of why you supposedly believe the opposite of some ancillary point I wasn't trying to make you have admitted why I do what I do is valid even to you.
> I sympathize with C-compatible API's to simplify an interface, though it's not my first choice.
It isn't about simplifying an interface: it is because in addition to the C++ ABI being itself fundamentally brittle (due to vtable ordering), you have to remember that some people use libstdc++ while others are now annoyingly using libc++ (I blame Apple, and I have absolutely no sympathy: they have ruined what little interoperability we used to have in this ecosystem they cared absolutely nothing for), and the ABIs between popular compilers is different; so when someone uses a C++ interface for their library I spend the next three days cursing their name and adding them to my "never let this person program anything ever again" list while I waste my time pulling crazy stunts to dynamically look up mangled symbol names and working around egregious incompatibilities in basic things like "when a C++ member function returns a structure, MinGW puts the hidden structure return pointer first while MSVC puts it after the hidden this pointer".
At this point I know the ABI of every major compiler on every major architecture, and I have been considering switching entirely to gcc and contributing a ton of patches that let me #pragma mark entire regions of code (due to header files) with specific calling conventions and layout ABIs, as this attitude that C++ is somehow appropriate for this purpose is creeping into more and more places as C++11 has caused more and more people to start using C++ without understanding its limits :/.
In the 3+ years I'm working in C++ without exceptions, I haven't missed them once.
When I first used Qt, I wondered how such a large framework could get along without exceptions. After writing some non-trivial Qt programs, I still noticed that there is really no need for exceptions, except when interfacing non-Qt libraries, where I simply caught and handled the exceptions in a small wrapper.
Finally, I got it: Qt uses the Null-Object pattern (not to be confused with Null values!) consistently, which is really in almost all cases the more elegant solution:
This is probably the only sane alternative to exceptions - optional types and result<T, E> types.
> We do not use C++ exceptions.
https://google.github.io/styleguide/cppguide.html#Exceptions
http://llvm.org/docs/CodingStandards.html#do-not-use-rtti-or...
- basic non-throwing initialization only constructor
- a "bool Initialize" method which does what the constructor would have done, but returns false on fail
- destructor as usual to clean up
But this is because I'm at Google where exceptions-are-no.And the destructor has to check for initialization before cleanup.
I'd be very suspicious of any failure avoidance system that relies on "user caution".
Now, true, some of these impose lesser burdens than others. Arguably, RAII imposes the least - but not zero. And if you forget with any resource, for that resource you are vulnerable.
And ultimately it should be possible to enforce that all resources are managed, because ultimately all resource interfaces have to be provided by the language runtime. To a certain extent enforcing user-defined invariants is always a matter of taste, but at the same time a language that makes it easy makes people a lot better at it.
Objects with an artificial invalid state are an antipattern in idiomatic c++.
std::ofstream file("example.txt");
if (!file.is_open()) return;
// ofstream will close in destructor.
And RAII doesn't even imply that the acquisition must happen via constructor. Edit: Technically it does, but the above pattern would not change if 'file' was a result of calling a free function or whatever.This is exactly not RAII. You acquired the resource and it might not be initialized. And it has the same problem: it's very easy to pass file around when it's not actually valid.
But full exception safety is obviously much more than just properly catching exceptions. I mean avoiding subtle traps like the ones here: https://herbsutter.com/gotw/_102/
Unless you have a bunch of code that just passes the object around without looking into it (so it won't fail there), and then when the crash finally happens, you have no idea where the invalid object came from.
This is really just another form of the billion dollar mistake, except you have invalid objects instead of null pointers (or in the worst case, you have both).
With an unhandled exception, you always have the context of where and why it happened (assuming you know the reason behind throwing it).
use abort() from stdlib.h
The exceptions crash the program. It's helpful and critical to debug the program and to stop it in case of bug/failure.
That said. I never use exceptions per-se. I just happen to get a std::out_of_bound_exception once in a while (for which there is nothing to be done, except crash :D).
Not sure what would happen if exceptions were disabled. Maybe the error handling would be disabled and program would keep running[1]. Maybe the STL would just call abort() instead of throwing an exception[2].
[1] That would be a disaster. Should never disable exception if so.
It ought to be possible to create impenetrable exception boundaries, such as:
- A compilation unit / file.
- Something identified as a “library” (perhaps based on namespace).
- The program itself.
If I want my “library” to automatically trap all exceptions that I throw, I should be able to. I shouldn’t have to worry that entire programs may crash because of mistakes from exceptions. Similarly, a programmer should be able to say, ONCE (regardless of any functions added in the future), “trap all exceptions from code in this file using this function” and be done with it.
And, if the language had been designed with this kind of visibility into exceptions, one would also have more useful information at the time they are trapped. For instance, obviously exceptions propagating all the way to main() have very little useful context but knowing that an exception is trapped in a file scope would be huge for debugging.
If you need more isolation, maybe you can make a design based on restartable servers.
GCC users have backtrace_symbols() for this.
(It was an interesting exercise to see how much of the ARM stack unwinding I could do in C++ rather than assembler; I managed it with only one asm instruction to get the link register and a lot of instruction-decoding C++)
Why? This is the best possible outcome. Continuing to run is the worst possible outcome from a correctness, security, and stability perspective. I can't imagine more of an anti-feature.
An unhandled exception should always be a catastrophic error -- exceptions are exactly for situations where the code is in an unexpected situation. If you keep running, the application is now running in that unpredictable state. You just want to bury your head in the sand at a library boundary but I don't see why that's desirable.
A well designed program (that isn't written in Java) should only have a handful of catch statements.
While you and I may agree that exceptions should be used for unexpected situations, nothing forces people to use them that way. A library programmer may have weird ideas about what warrants an exception. If my application appears to be functioning correctly, I should not have to risk crashing because of something that cannot be proven to affect my program in a significant way. My program may be trying to remain stable (e.g. a GUI for a user), and the user may well not care if my program has encountered an issue if it means throwing out their last 10 minutes of unsaved work. Some programs like CAD tools may run for days, and even partial results with logged errors can still be important to preserve in lieu of stupid crashes.
That's the correct way to do it; blanket ignoring all unhandled exceptions from a library is just very strange by comparison. If there is a specific exception that you want to ignore, by all means ignore it and document it heavily. But you don't know if every exception is irrelevant or potentially data corrupting.
Even if I do have a catch-all, what tells me that it is a "library" exception? They might have thrown a generic std::exception with a vague string description. They might have thrown an "int". At some point what I really want is proper language and compiler support for those boundaries so I can know exactly where an exception came from, and can trap it at those boundaries (or ask the library maintainers to do so).
A function could just not use exceptions at all and just call abort() on error, what are you going to do then?
There isn't really a concept of library boundary in C++; you just have compilation units at best. At worst, you have a library that's implemented entirely as headers. What happens when the exception originates in your code but goes through the libraries call stack (because it was a call on a passed-in object or callback)? What you are asking for is likely impossible.
Here's another one: C++ allows programmers to overload operators, but doesn't enforce anything with regard to the overloaded behavior. I can make "+" actually subtract, or make "<", "==", and ">" always return "true", or have a function called "add_two" that actually adds three! When you find a language that prevents people from using it incorrectly, please let me know. Until then, I'll have to follow my rule of thumb that a library that crashes randomly -- whether it's caused by SEGFAULTing, failing to follow it's own exception specifications, or for any other reason -- is buggy and I won't use it.
*
In another comment, you say that you would like a language that enforces internal boundaries. It's not clear to me how that would work. Let's use a specific example:
Imagine I am using a garbage collector library, and I ask for memory. It's a copying collector, and my request ends up promoting objects from one generation into another. Unfortunately, more objects survive than expected, so there isn't room in the target generation's pool. The library throws an exception, fails to handle it, and an internal exception specification doesn't include the exception causing us trouble. In other words, the programmer listed which scenarios were handled, and this one was not on the list. And, of course, we have a boundary like you had asked for.
What can cross that boundary? The library doesn't have the memory I asked for. If we pass the exception across the boundary, it's not clear what purpose the boundary serves. It's also not clear what I should do with that exception: it's an internal detail. Even if I can figure out that we essentially have a buffer that's too small, I don't have access to that buffer (so I can't make it any larger), and I probably don't have access to the functions needed to start promoting survivors from our too-small generation to make room. How would the proposed boundaries handle this problem?
What makes a library sufficiently buggy? The set of conditions leading to a crash from an exception at run time may not be known to the library maintainer, even in a “good” library. The crash in your particular program, caused by the library, may not occur for awhile, after which you already depend on the API. With a normal error-handling scheme, this would still be OK because you could trace the error.
Programs can already crash in enough ways, without C++ introducing more. I can debug even severe memory errors in fairly straightforward ways (e.g. trap in debugger, or run "valgrind", or other instruments). I hate debugging a “crash” that is essentially C++ converting a trivial mistake from someone’s error-handling code into a fatal, untraceable run time error. When I see terminate() I know I have a problem. I essentially have to start using "grep" for every possible "throw" statement (hopefully finding something in recently-committed code), trying to match functions that might be related to what the program seemed to be doing when it died. And since C++ exceptions provide very little help when debugging, one has to go to extra effort to add information to every exception (which is useless if the exception at run time didn’t come from your own code).
C++ exceptions are just not “better”, like a lot of C++ changes. They can’t break crucial debugging mechanisms like stack-traces and expect the result to be better.
What debugger are you using that doesn't provide a full stack trace on an uncaught exception?
By the way, you can get very close to this behavior today with `std::set_unexpected` ( http://www.cplusplus.com/reference/exception/set_unexpected/ ). That page says that the function you set as the unexpected handler must "end either by terminating (calling `terminate` or some other method, such as `exit` or `abort`) or by throwing an exception (even rethrowing the same exception again). If the exception thrown (or rethrown) is not in the function's dynamic-exception-specification but `bad_exception` is, a `bad_exception` is thrown" (emphasis added).
*
> Programs can already crash in enough ways, without C++ introducing more. ... When I see terminate() I know I have a problem. I essentially have to start using "grep" for every possible "throw" statement (hopefully finding something in recently-committed code), trying to match functions that might be related to what the program seemed to be doing when it died. And since C++ exceptions provide very little help when debugging, one has to go to extra effort to add information to every exception (which is useless if the exception at run time didn’t come from your own code).
For the record, I'm not really a fan of exceptions or fancy error handling code. I subscribe to the school of thought that you probably have a main loop (which handles requests, or waits for user input, etc.) and that loop should have your single try/catch block ( http://www.artima.com/intv/handcuffsP.html ). You handle exceptions by giving up on what you were trying to do, and perhaps letting the user know. You then go to the next loop iteration.
That is, I almost never see a need for two try/catch blocks in a program ( https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexi... ). Error handling code is especially notorious for not being tested and therefore not doing what it should. Therefore, error handling code beyond "abandon the current request" is fishy to me.
And I agree that one of the few things I miss when I work in C++ is exceptions that carry a lot of information automatically. In C++, if you want the exception to carry file/line number information, you have to add it yourself (probably via a macro: "#define THROW_EX(X) throw AppException((X), __FILE__, __LINE__)" or something similar). And that doesn't even address nested exceptions. I rely on a lot of logging, and the ability to reliably reproduce the problem while running it in a debugger.
I believe the Committee, so far, has avoided bringing exceptions on par with you see in other languages because doing so would have an unusually high execution and/or implementation cost compared to other aspects of C++. It's entirely possible that this decision will be revisited: C++14 and C++17 feel to me like they were very strongly influenced by Java.
noexcept is a bullshit feature if you care about stability
A program that loses user data on a crash (any crash), is just not designed for reliability, period.
A reliable program will probably use transactional storage and periodic checkpoints.
Look-up "crash only software".
Uh huh. And how do you feel about sefaults?
I didn't follow the development of noexcept, so I can only guess at the motives. By and large, there were three complaints about exception specifications that I am familiar with: (1) by requiring stack unwinding when a no-throw specification was violated, they often caused worse performance (or, at least, didn't allow an optimization opportunity); (2) generally, the important question is whether a function might throw, not which exceptions it might throw; and (3) the rules around when exception specifications affect a function's signature -- e.g., does a pointer to a function have to match the specification exactly? -- were convoluted. I think it was reasonable for the Committee to focus on those issues.
Existing unmarked functions would be expeced to possibly throw everything, while functions with throw specifications would be statically checked.
You can call the later from the former, but to do the reverse you need an explicit try/catch. Some form of throw(auto) would enable automatic deduction of exception specifications for e.g. template code.
Dyanamic exception specifications will be removed fron the language in c++17, so the synax is open to be reused for such a feature in the future.
It'd be nice to see compilers infer the exception behavior themselves and do these optimizations when appropriate.