Live data from Hacker News

C++'s `noexcept` can sometimes help or hurt performance

16bpp.net

151–160 of 166 posts

Re: C++'s `noexcept` can sometimes help or hurt performance

#151

Earlier quoted context omitted.

Well, given that qsort and bsearch take a function pointer and call it, that function pointer can easily point to a function that throws. So I think this applies to all implementations of qsort and bsearch. Especially since there is no way to mark a function pointer as noexcept.

> Especially since there is no way to mark a function pointer as noexcept. There is, noexcept is part of the type since C++17. In fact, I prefer noexcept function pointer parameters for C library wrappers, as I don't expect most libraries written in C to deal with stack unwinding at all.

Oops, you're right, I hadn't checked that this had changed in C++ 17.

Re: C++'s `noexcept` can sometimes help or hurt performance

#152
post #131

Earlier quoted context omitted.

https://eel.is/c++draft/alg.c.library#4 Any library implementation that is C++ compliant must implement this. I'm pretty sure that libstdc++ + glibc is compliant, assuming sane glibc compiler options.

but to me these are - again - a user induced problems. I'm interested if a user doesn't do stupid things, should they still afraid that a standard extern C code could throw? Say, std::sprintf() which if I'm not mistaken boils down to C directly? Are there cases where C std lib could throw without a "help from a user"?

I don't think anything in the C parts of the C++ standard library throws its own exceptions. However, it's not completely unreasonable for a third party C library to use a C++ library underneath, and that might propagate any exceptions that the C++ side throws. This would be especially true if the C library were designed with some kind of plugin support, and someone supplied a C++ plugin.

Re: C++'s `noexcept` can sometimes help or hurt performance

#153
post #131

Earlier quoted context omitted.

but to me these are - again - a user induced problems. I'm interested if a user doesn't do stupid things, should they still afraid that a standard extern C code could throw? Say, std::sprintf() which if I'm not mistaken boils down to C directly? Are there cases where C std lib could throw without a "help from a user"?

https://eel.is/c++draft/res.on.exception.handling#2 I general functions from the C standard library must not throw, except for the ones taking function pointers that they execute.

perfect again, thank you!

Re: C++'s `noexcept` can sometimes help or hurt performance

#154
post #82

Earlier quoted context omitted.

As proven by musl versus glibc issues, that possibility is mostly theoric, with plenty of gotchas in practice.

musl and glibc are both compatible for the POSIX portion of the API they provide. GCC also has lots of GNU specific functions but so what?

Square peg into rectangular hole.

ISO C and POSIX have plenty of implementation defined behaviours.

Re: C++'s `noexcept` can sometimes help or hurt performance

#155

Earlier quoted context omitted.

That would have been too limiting since there are many (e.g. C) functions that can never throw but are not marked noexcept. Not being able to mark your function noexcept just because you call some standard math function would be counterproductive.

There were ways around this. C functions in the standard library could easily be marked noexcept, for one. Extern C could also imply noexcept. Also, explicit try/catch blocks could be required when calling a potentially-throwing function from a noexcept function - slightly annoying, but not a huge problem in practice. Overall this was just another case of the C++ community's preference for speed over safety and robus…

> There were ways around this. C functions in the standard library could easily be marked noexcept, for one.

C++ standard library function yes, C standard library functions, incloding those imported into C++ are more complicated since on most platforms those are not provided by the C++ implementation but some other lower level library. Third-party libraries are the bigger concern though.

> Extern C could also imply noexcept.

In theory this might be correct but in practice this will cause problems with C functions that take callbacks which the user might want to throw from. These are already problematic especially since the C code won't unwind anything but you'd still need to concern yourself with potentially breaking user code.

> Also, explicit try/catch blocks could be required when calling a potentially-throwing function from a noexcept function - slightly annoying, but not a huge problem in practice.

Yes, but avoiding that is the whole point. The try-cach for potentially when you call potentially throwing functions is already implicitly provided by current noexcept and if your noexcept function only calls only noexcept functions then the compiler can already elide all that.

> Overall this was just another case of the C++ community's preference for speed over safety and robustness.

Not at all. If that was the case then noexcept would only be a compiler hint and exceptions bubbling up to noexcept functions would be undefined behavior. Arguably that would be better than what we have now.

Re: C++'s `noexcept` can sometimes help or hurt performance

#156

Earlier quoted context omitted.

> All noexcept does is catch any exception and immediately std::terminate. I don't think this is a decent interpretation of what no except does. It misses the whole point of this feature, and confuses a failsafe with the point of using it. The whole point of noexcept is to tell the compiler that the function does not throw exceptions. This allows the compiler to apply optimizations, such as not needing to track down…

Except the compiler still needs to ensure that if an exception bubbles through a noexcept function, std::terminate will be called, even if the exception were caught at some level above. So it still needs to keep track of the noexcept frames, even when inlining the noexcept function. Generally what a language feature is intended to do is less relevant than what it actually does, over time. Just like the "inline" keywo…

> Except the compiler still needs to ensure that if an exception bubbles through a noexcept function, std::terminate will be called, even if the exception were caught at some level above.

That's the failsafe I mentioned.

> Generally what a language feature is intended to do is less relevant than what it actually does, over time.

Not true, and again this take misses the whole point. The point of noexcept is to declare that a function does not throw exceptions. If a function is declared as noexcept, the whole point is that it does not throw exceptions. How the runtime handles a violation of this contract is something that only expresses in a bug. The same applies for exceptions thrown in destructors. It makes no sense to describe destructors as something that calls std::terminate .

Re: C++'s `noexcept` can sometimes help or hurt performance

#157

Earlier quoted context omitted.

There were ways around this. C functions in the standard library could easily be marked noexcept, for one. Extern C could also imply noexcept. Also, explicit try/catch blocks could be required when calling a potentially-throwing function from a noexcept function - slightly annoying, but not a huge problem in practice. Overall this was just another case of the C++ community's preference for speed over safety and robus…

> There were ways around this. C functions in the standard library could easily be marked noexcept, for one. C++ standard library function yes, C standard library functions, incloding those imported into C++ are more complicated since on most platforms those are not provided by the C++ implementation but some other lower level library. Third-party libraries are the bigger concern though. > Extern C could also imply n…

> C++ standard library function yes, C standard library functions, incloding those imported into C++ are more complicated since on most platforms those are not provided by the C++ implementation but some other lower level library. Third-party libraries are the bigger concern though.

Since noexcept is a compilation-level hint, it only matters that the declaration contains them in the headers, not who provides the implementations. And since C functions can't deal with exceptions thrown from callbacks, it would make sense to annotate any function pointer that you provide with noexcept as well.

> Yes, but avoiding that is the whole point. The try-cach for potentially when you call potentially throwing functions is already implicitly provided by current noexcept and if your noexcept function only calls only noexcept functions then the compiler can already elide all that.

The current implementation calls std::terminate() if an exception is caught. That needn't be the case in practice: you could well handle the exception in a meaningful way and continue execution. Also, having the programmer explicitly do this is valuable in itself, even if they also just call std::terminate(). For example, with the way noexcept is implemented today, you have no notification if a function you're calling goes from noexcept to potentially throwing until your program actually crashes. If noexcept was an actual compiler-checked keyword, your code would stop compiling if one of the functions you rely on started throwing exceptions, and you could decide what to do (maybe catch it, maybe find an alternative, etc).

> Not at all. If that was the case then noexcept would only be a compiler hint and exceptions bubbling up to noexcept functions would be undefined behavior. Arguably that would be better than what we have now.

Crashing the program is of course better than UB. But it's still the worse possible thing to happen other than that. It basically makes noexcept functions be the most scary functions to ever call, instead of being the safest. And if you want to write a piece of code that can never throw an exception, the compiler still won't help you in any way to do that, it's up to you to do it correctly or crash.

Re: C++'s `noexcept` can sometimes help or hurt performance

#158

Oh man, don't get me started. This was a point in a talk I gave years ago called "Please Please Help the Compiler" (what I thought was a clever cut at the conventional wisdom at the time of "Don't Try to Help the Compiler") I work on MSVC backend. I argued pretty strenuously at the time that noexcept was costly and being marketed incorrectly. Perhaps the costs are worth it, but none the less there is a cost The reaso…

> I argued then that if instead noexcept violations were undefined, we could ignore all this, and instead just treat it as the pure optimization it was being marketed as (ie, help prove a region can't throw, so we can elide entire try/catch blocks etc). The reaction to my suggestion was not positive.

So instead of helping programmers actually write noexcept functions, you wanted to make this an even bigger footgun than it already is? How often are there try/catch blocks that are actually elideable in real-world code? How much performance would actually be gained by doing that, versus the cost of all of the security issues that this feature would introduce?

If the compiler actually checked that noexcept code can't throw exceptions (i.e. noexcept functions were only allowed to call other noexcept functions), and the only way to get exceptions in noexcept functions was calls to C code which then calls other C++ code that throws, then I would actually agree with you that this would have been OK as UB (since anyway there are no guarantees that even perfectly written C code that gets an exception wouldn't leave your system in a bad state). But with a feature that already relies on programmer care, and can break at every upgrade of a third party library, making this UB seems far too dangerous for far too little gain.

Re: C++'s `noexcept` can sometimes help or hurt performance

#159
post #114

Earlier quoted context omitted.

> Java has the first part down, for the class of checked exceptions: a function that doesn't throw can't call functions that do (except in try/catch blocks, but that's largely irrelevant). That's not actually true, it's possible to do "sneaky throws" ( https://www.baeldung.com/java-sneaky-throws ) of a checked exception from a method which isn't declared to throw that checked exception. The classic example is Class.n…

Sure, but that's essentially the same as using explicit jumps through raw assembly instructions to go around C++'s destructor guarantees. That is, when your Java process runs non-Java code, of course this can defeat certain Java guarantees. No programming language can make promises for semantics of external code like this.

That's still the case in pure Java code. The "Class.newInstance()" method is a public method on the core Java API, calling "MyClass.class.newInstance()" is mostly equivalent to "new MyClass()". And the generics trick in the "sneaky throws" article I linked is also pure Java code, without any calls to "sun.misc.Unsafe".

Re: C++'s `noexcept` can sometimes help or hurt performance

#160

Earlier quoted context omitted.

Except the compiler still needs to ensure that if an exception bubbles through a noexcept function, std::terminate will be called, even if the exception were caught at some level above. So it still needs to keep track of the noexcept frames, even when inlining the noexcept function. Generally what a language feature is intended to do is less relevant than what it actually does, over time. Just like the "inline" keywo…

> Except the compiler still needs to ensure that if an exception bubbles through a noexcept function, std::terminate will be called, even if the exception were caught at some level above. That's the failsafe I mentioned. > Generally what a language feature is intended to do is less relevant than what it actually does, over time. Not true, and again this take misses the whole point. The point of noexcept is to declare…

How do you feel about the inline keyword?

Also, of course destructors are not "something that calls std::terminate", because they do many other things.

For function definitions, noexcept is perfectly equivalent to wrapping the body of your function in try {} catch (...) {std::terminate();}. In fact, noexcept doesn't even add any extra optimization options for the compiler: the compiler can already use the presence of such a block to decide that your function can't throw exceptions and optimize accordingly. Whether it can also ellide this block is a different matter, and noexcept doesn't help with that. It's just a nifty piece of syntax instead of this block.

Conversely, the noexcept declaration on the function doesn't allow the compiler to deduce anything about exceptions not being thrown inside the function, because the standard doesn't forbid throwing exceptions.

The only purpose noexcept serves other than a try/catch block is when used with declarations - there is indeed a difference in how the compiler can optimize a call to a function declared `extern void foo() noexcept;` and a function declared as `extern void foo();`

Post reply on HN