De-fragmenting C++: Making Exceptions and RTTI More Affordable and Usable - Herb Sutter CppCon 2019
Вставка
- Опубліковано 18 гру 2024
- CppCon.org
Discussion & Comments: / cpp
Presentation Slides, PDFs, Source Code and other presenter materials are available at: github.com/Cpp...
-
De-fragmenting C++: Making Exceptions and RTTI More Affordable and Usable
A fundamental reason why C++ is successful and loved is its adherence to Stroustrup’s zero-overhead principle: You don’t pay for what you don’t use, and if you do use a feature you can’t reasonably code it better by hand. In the C++ language itself, there are only two features that violate the zero-overhead principle, exception handling and RTTI - and, unsurprisingly, these are also the only two C++ language features that every C++ compiler has switches to turn off and that are regularly discouraged or even banned. This matters because not using these features is the largest current cause of fragmentation of the C++ community into incompatible dialects, and the cause of recurring problems including type confusion security vulnerabilities arising from “didn’t down-cast using dynamic_cast because that would be too slow.” This talk is about ongoing long-term efforts to try to unify the community in this area, not by replacing exceptions and RTTI, but by doubling down: fully embracing exceptions and RTTI, and improving them so they can be zero-overhead too.
-
Herb Sutter
Herb is an author, designer of several Standard C++ features, and chair of the ISO C++ committee and the Standard C++ Foundation. His current interest is simplifying C++.
-
Videos Filmed & Edited by Bash Films: www.BashFilms.com
*-----*
Register Now For CppCon 2022: cppcon.org/reg...
*-----*
I like his proposals, that would actually make my life as a C++ programmer better
same, but was it accepted ?
@@velvounet 41:44 Quote: "And this is a long-term thing, like, please do not ask if it's in C++20 or C++23, this is a long [...] endeavor that is still in its early phases."
Based on that statement, I wouldn't be surprised if the proposal hasn't even reached a committee-reviewable state.
There are a lot of exciting potential future c++ features Herb has talked about. And I can't wait for the day they finally arrive. I guess we just gotta be patient.
This man is GENIUS. No doubt about it. No discussion about it is allowed. The thing that concerns me however: RAII: The main difference between throwing the exception and returning error code is: Throwing an exception from the constructor considers the object not being constructed, so it's destructor is not being called. All the objects that have been constructed so far (the class attributes, base classes) are being destructed, while the stack is unfolding, up to, but excluding the destructor of the class whose constructor threw. This is so important difference, I hope this new syntax is supposed to support this approach as well.
Another "isomorphic" analogy was in x86 assembly coding, where it was common to return error state from function in CPU's Carry flag, and in case of error, the return value (EAX/RAX register) held error code. When I was writing large x86 ASM code long ago, doing error handling that way was by far the simplest and felt completely natural. This was much easier than consistent error handling in C ("if (retval) return retval;" after every function call, and no real return value available).
So, you mean like C's "errno.h" way of handling errors?
That shirt is amazing. Herb is awesome and so positive.
He’s the man! And Herb Sutter too. What a legend. Nice talk
Now two years later, are there any progress on these ideas for exceptions and RTTI?
It's not in C++23, so who knows.
I've finally gotten around to reading *Clean Code* recently, and the Java focus of the book is mostly a small annoyance to a c++ programmer like myself. But interestingly Uncle Bob claims (chapter 7) that it is better to avoid checked exceptions (which have a similar syntax to that proposed here for static exceptions in c++: you list the exceptions that might be thrown in the signature). I don't claim to understand the details of Uncle Bob's argument nor those of the proposal here. I just hope the committee has talked to some Java people and taken whatever is relevant from their experience on board.
Can someone explain what "value semantics" mean in the context at 34:30? Is it the same as using "copy" as opposed to "reference/pointer"?
The down_cast code blew my mind. Get the ptrdiff_t between two vtables in memory to know if a down-cast is safe? Genius!
If you look at Phil Nash's talk, the "error" type that every function has to use as an error relies on virtual functions to check what exact error was thrown (errors have categories; those categories are classes that have virtual functions to whom the check is delegated).
With this requirement, I think this solution violates the idea of zero overhead- how often do you see error codes use virtual functions?
That all depends on the question you ask. The typical question you ask when you catch an `error` is "does this `error` use this category and this error code value?" That is, you are looking for specific errors, so you provide the category + error-code to test against. That should be a trivial byte-comparison test, nothing that requires a virtual function call.
Even if you want to extract the error payload from the `error` object, you don't need a virtual function. You merely need to know what category it contains. Since categories are types, you just invoke a static function of that type to convert the error code value back into whatever it needs to be. No virtual call needed.
A virtual interface would only be needed if you have absolutely no idea what category the error contains. And at that point... can you really know anything about the error code value if you don't have the category?
C++ compiler supporting union return types sounds awesome - darn near functional programming. Could it eventually be generalized?
You can return an std::variant (if that's what you mean by "union return types").
I mean technically, C++ supports union return types today. Unions are legitimate types, and you can initialize a union and return one by value.
The problem is that unions have no idea what state they currently have. So you'd have to return a struct containing a union which tells what value it stores. Or more properly, a `std::variant`. Which is a C++17 type. So the general case is already available to you.
The real innovation seems to be the language supporting selective propagation down the right path (error propagation) automatically.
The std::variant other replies are referring to is what is commonly called a tagged union, and it's typically the structure used to implement union types in functional languages. So aside from the syntactic sugar, it's already generalized.
Super ideas! But for my perspective the exceptions is a general problem. Because it is a side effect in your functions. As it is not part of the function signature this is something that you should not expect from the function.
yes, some exception specification would solve the problem.
I was a while ago wondering why compilers didn't do this optimization when throw is inlined to same function with catch and throw is a simple type fitting to a register. Because in that case whole throw could turn into simple jump directly to catch. But I guess none wants to work that much in special case optimization when none anyway uses exceptions when performance is required for throw path.
Sometimes it does, however it gets combinatorially harder so in real(large enough) applications it is just delegated until more info is present
With the segment regarding downcasts around 1:23:00, what if the class doesn't have a vtable? From what I understand if there is no vtable if there are no virtual functions.
If there are no virtual functions dynamic_cast (the current one) will not work. In fact, it won't even compile.
godbolt.org/z/7QAVCo
1:03:50 That's nice, and makes perfect sense, but it'll make the ecosystem extremely reliable on tooling and static analysis, because reporting bugs is still quite useful. By not using exceptions, there's no other way for the user/programmer to know what went wrong unless the program/code, or its dump/output, is properly analyzed -- considering that, in general, those precondition errors will generate no output whatsoever (most probably, the program will just crash), and I may be wrong on this btw.
Not saying it's a bad thing, quite the contrary; I just hope tool authors (compilers, static checkers, etc) catch on those new changes as fast as the community needs them to.
Taxonomy : 29:45 I worked in a big company with a lot of C++ code, and ... I was so sad that B class were handled as C class ................... I always learned the way it is presented here.. The reason was that if there's a programming bug, we don't want the whole program to terminate when a client uses the program .. which I understand ? Though I don't like that design principle at all, especially because preconditions and postconditions should never be CHECKED on release !!
27:30 arent assertions not optimized out at deploy build...? (And violations become UB)
Good that they make exception handling cheaper but it doesn't address the cost of writing resource leak free exception safe code in the client. This is no easy task; in fact Sutter himself wrote two books about the subject which only addressed C++ technical issues. It skips over real life programming e.g. when compound functions have to invoke multiple subsystems and roll everything back in case no success. I would have preferred that C++ does not go for the idiomatic route and e.g. support a std::expected route as well. Let software engineers decide what mechanism to use for error handling since mostly they are the experts in their domain and not a committee.
He forgets one group: those who just don't like Exceptions.
25:45 And that's exactly what "Result-Type first" languages encourage. But C++ is a "Exception first" language, or at least that is the way it is tought.
WEN??!?
It seems to me that the biggest problem with exceptions is missing from the analysis: no compiler/statc-analyzer can validate exception safety of arbitrary code.
And then nobody considers the obvious choice: if there are no bad-allocs to handle there is no need for exceptions at all. (a) there are very few left reasons to throw an exception, (b) new(nothrow) will cover all the 0.00001% of the cases where memory allocation can really fail, (c) factory functions will cover remaining 0.00001% cases where constructor can actually throw something else but bad-alloc.
And until that time we will call terminate from the new-driver and keep all other exceptions unhandled and listen to more meaningless lectures on how great are exceptions.
"very few reasons for exceptions" seems more a personal opinion than something proven.
It is obvious that one can write code witout exception. This does not implies there is no reasons to use them. One can write any program with bare bits in a sequential file... does not mean it is a good idea.
Most important part of this talk: you can outright ban exceptions from your codebase with -fno-exceptions. I just saved you an hour of your life.
People could also just acknowledge that C++ has a diverse user base with opposing needs. No way we will turn on exceptions on our hard real-time systems.
What are your counterpoints to his proposal?
Nobody is forcing you to turn on exceptions though. All he is doing is making the whole thing more attractive to people who traditionally stayed away from them. I think that's a good thing, despite not caring for exceptions myself.