In the cases we would have a crash that could trigger an exception but doesn’t because we have a noexcept statement, what would be the most kosher way to disable it?
I searched for noexcept and macro and found this:
that suggests the some undefs could be added in juce_PlatformDefs.h.
Is it already possible to re-enable these in a different way, can we just undef all of them using #define noexcept without fearing these to be reset and active (so no exception) in other code ?
If none exists would it help to have in future a NOEXCEPT or JUCE_NOEXCEPT macro that would just unambiguously define it to noexcept but could be set by user to nothing to re-enable exceptions?
“noexcept” does not mean exceptions are disabled. It signals to the compiler that the function is written so that it does not throw exceptions. But if it throws an exception anyway, the program will be terminated. (Which will happen anyway without the “noexcept” if nothing is catching the exception.)
“noexcept” is a hint to the compiler that it doesn’t need to bother inserting any exception handling into the compiled code, besides a call to the abort() function or equivalent. This may result in more optimized code.
If abort() is called, this should be caught by the debugger and you should be able to see the call stack that caused the abort happening. (At least Visual Studio’s debugger does that.)
Juce can liberally use “noexcept” in the API because it doesn’t really throw exceptions itself. (Not all of the functions that don’t throw exceptions are marked as “noexcept”, though. The reason for that should be obvious : there would be thousands of functions/methods to go through in the old code.)
Do you have some practical use case where this would be important? Have you noticed a Juce function that throws an exception even though it is marked “noexcept”? The fix wouldn’t be to change how the “noexcept” keyword works in the code, but the Juce team would have to fix the Juce code instead.
Thanks, i know that exceptions are not disabled and I think I also understand what noexcept means,
But my discussion was more in the particular case of having say an object is deleted twice in a code where noexcept is used: with no noexcept on it should be captured in this code,
but now it would not break in a debugger in that code with a useful stack, but instead may give you a sub-optimal exception that is not very helpful? (I see system exceptions all the time in the console windows for which I don’t know what to do with i.e. no stack to investigate…)
So my use case and noob question would be to try answer your question:
Is it still going to throw an helpful exception (with a stack maybe) if the code that triggers the delete has a noexcept (so it won’t itself throw an exception) ?
The difference here is I sure can have a system exception in the end telling me that something was wrong but it would not be as helpful as an exception triggered in the code that generated the delete.
That is just an use case example to try to identify a potential need that is more general on noexcept,
that I try to build so that I gain understanding on it.
So that someone could answer would it sometimes be useful or not to be able to disable this noexcept statement once and for all while debugging and then being able to reactivate them once done.
More recently, I come from .net environments where we always have exceptions in the non native code, so even if I do also have a some experience (old knowledge though!) on C++ memory management and exceptions I am not 100% waterproof on that yet so I appreciate feedback and pardon my naive questions!
C++ exceptions don’t cover things like memory access violations (aka segfaults) or divisions by zero. In any case, if those happen, the debugger usually will show where in the code the error happened. (Confusingly, Visual Studio/Windows calls also those kinds of errors “exceptions”, but they don’t have anything to do with C++ exceptions…)
Weird, am I confusing things then because on OSX i do get memory access exceptions (SEGFAULTs actually) and on Windows I also get exceptions (when they are generated in non except code i suppose). or are u saying that in the c++ generated code it won’t trigger an exception anyway?
So it seems it works at least when no noexcept is used in the scope of interest?
In .net btw we also don’t have always divide by zero exceptions if the scalar type is a float/double as an example where +inf and -inf are excpected.
When you debug the following code in Visual Studio and enter “0” into the console, the debugger will notice an integer divide by zero happened and says it’s an “unhandled exception”. But it’s not the kind of exception that you can catch with C++ facilities, so “noexcept” & co are not going to do anything for it. The same goes for accessing memory that was already freed or wasn’t ever allocated and so on.
int main()
{
int x = 1;
std::cin >> x;
std::cout << 100 / x << "\n";
return 0;
}
OK thanks, that helps. But Daniel in the other thread was referring to a case where we could have noticed something but ‘sadly’ it would not because noexcept was used, I’d just like to understand what he meant with more precision there then.
A segfault is something completely different to an exception as it happens on a much lower level.
Various languages have language-own exception mechanisms which are managed through some extra code logic behind the scenes that gets triggered in case the exception gets thrown, a bit like some special function getting called conditionally. C++ exceptions are such a mechanism (I think e.g. Obj-C has its own exception mechanism etc), you explicitly throw them in your code by the throw keyword which will then trigger this exception handling logic and lets you break out of your functions code function flow. This does not happen in case of a segfault or a division by 0. Of course you could handle it yourself like
float divide (float a, float b)
{
if (b == 0.0f)
throw std::runtime_error ("you divided by 0!");
// code below won't be executed if the exception has been thrown
return a / b;
}
If the compiler knows that it never has to handle that alternative code flow that happens if an exception gets thrown, it can produce faster code.
“noexcept” doesn’t mask errors. On the contrary, it will be very obvious that a C++ function marked “noexcept” threw a C++ exception anyway, since the whole program will be terminated by calling abort(). But none of this has anything to do with “system exceptions” like segfaults/access violations.
Unless a true c++ exception (now I understand it would be a c++ generated exception only in that case and that i would not be because of a delete thanks!) could have been triggered but now won’t because of noexcept, and will crash only much later.
But at the same time, I may still have a stack then will actually test this today , it should be easy to reproduce thanks.
Sorry, I am having real trouble understanding what you mean by all this…
To make the above example I posted dealing with a system exception (integer divide by zero) more concrete in terms of “noexcept”, here’s a version that does the divide in a “noexcept” function :
void test_noexcept() noexcept
{
int x = 0;
std::cin >> x;
std::cout << 100 / x << "\n";
}
int main()
{
try
{
test_noexcept();
}
catch (std::exception& ex)
{
std::cout << ex.what() << "\n";
}
return 0;
The error is still a system exception and immediately causes the program to terminate. If that happens while debugging, Visual Studio will show it was a divide by zero. The “noexcept” doesn’t make any difference here.
Yes i just tested that myself in windows, so I am confused now on the case where noexcept would hide exceptions in debug mode as it seems hard not to see an exception popping up with a nice stack?
Note that I do have a stack so I can’t see a reason why noexcept would be a problem anytime (at least in debug mode) ?
See:
I’ve tried explaining multiple times : “noexcept” does not hide/mask C++ exceptions, it rather makes them completely obvious by stopping the program immediately.
You didn’t test C++ exceptions in the above code, though…
There’s really no cost or downside to “noexcept”. They are intended to be used for functions that shouldn’t have any C++ exceptions anyway. It is possible that a programmer (like a programmer developing the Juce library) makes a mistake and marks a function “noexcept” but the function throws a C++ exception anyway. But even in that case things would be pretty good, because the result would be immediate program termination and that could probably be easily debugged. Incidentally, the result would be program termination without “noexcept” too, if the code doesn’t have a try/catch block that deals with the exceptions.
True but in your code having noexcept would still not change anything because as you explained it is not a c++ exception but a div by zero processor error intercepted in system not our code,
, but in that new code (thanks to your remark i built more interesting material below!)
int throwAtMe(int val) noexcept
{
if ( val == 0) throw std::invalid_argument( "received zero value" );
return 42 / val;
}
int main()
{
try
{
throwAtMe(0);
}
catch (std::exception& ex)
{
std::cout << "Captured " << ex.what() << "\n";
}
return 0;
}
I can see the effect now:
If you remove now the noexcept you will be able to capture the exception in the main code,
which I actually don’t like (you’re masking a problem instead of getting a crash!) even if I do understand that it could be used properly to have a nicer exception handler which logs post-mortem info or the like but in that case you would have to also intercept system traps to be convincing anyway …
This is really a philosophical debate about when to use exceptions and what constitutes a “failure”.
In your example I would argue that passing in 0 violates a precondition contract and so should crash i.e. not validate the input at all and don’t even attempt to throw an exception.
If a function throws, it should really be in a recoverable situation.
(There are other arguments about throwing exceptions during tests to log but that’s a bit off topic).
I agree, my snippet is just an example that shows actually a case where noexcept does have an effect for educational purpose when someone will search for the same keywords.
Like I also mentioned, in case where it would crash, more advanced software can also intercept the exception or the system error even and re-vectorise it as a C++ exception, apparently VCV Rack does that (thanks @xenakios for this reference) to log post-mortem data before dying …
But understandably, that would be more at the charge of the implementer to do so if/when needed with all the risks it represents to alter the systems traps…
In all cases, I am more confident after doing some real testing about what noexcept does in JUCE codebase and also like the fact that JUCE does not try to catch exceptions, and just lets it blow so that we can notice it (in most cases) and take action.
I now don’t even think a macro to redefine it would such a great help anymore as I learned more about it.