a rant on noexcept....
Over the past few months I've been trying to integrate noexcept into my C++ code. On the surface this sort-of new feature looked decent. For the record, even though I know C++ has its caveats I quite like it, and I am very 'pro' exceptions (pro/con pro, not pro as in I know everything). I will (and have in the past) happily defend exceptions as a superior form of run-time error handling. So noexcept should be right up my ally...
But no, in short noexcept is currently a mess and should be avoided...
The idea behind noexcept is that you can tag a function (member function, normal function, operator, whatever) as noexcept like:
void Func() noexcept { /*... do stuff here that doesn't throw an exception...*/ }
which declares to the compiler that the function does not throw an exeception. The idea being that code can later choose a more optimal algorithm if you know a function doesn't throw. You can test this with the noexcept operator:
noexcept(Func())
The thing is noexcept is much like const, it gets everywhere. Once one function is tagged as noexcept, every function used in it needs to be noexcept (or nearly, as try/catch blocks can work around it), which then transitively propagates to any functions they call, and on and on... Much like you just can't add one or two const's in a program and hope all goes well, similarly with noexcept. Its either all-in or not-at-all. Except things are even worse with noexcept. const simply applies to types, classes, and their member functions. noexcept applies to all functions, not just some functions. Doing it 'right' and noexcept ends up everywhere. Its starts cluttering code and getting everywhere. I know its C++, and its not the nicest syntax, but still...
But then things start to get nasty, there's two really big problems that aren't immediately obvious. The first is the noexcept operator and its interaction with templates. As soon as you add templates into the mix, you don't know exactly what functions are being called, so you can't just look at the code and know 'ya that's a noexcept function' or 'no that function clearly throws'. Maybe it throws, maybe it doesn't, depends on the template parameters. So the idea is to test them with the noexcept operator. The simple example online and in the docs are things like:
void FuncC() noexcept( noexcept(FuncA()) && noexcept(FuncB()) );
The above example would declare a function FuncC() noexcept if FuncA() and FuncB() are both noexcept. So for simple function boiling down the logic to a simple state is possible if not a bit annoying. But anything remotely complex, and you're ready to throw your computer out the window. In many cases the noexcept specification becomes as complex, if not more so, than the code itself. These things start to become monstrous, and trying to keep the code and specification cohesive while fixing bugs, making changes, refactoring... to say its a nightmare is an understatement, and completely intractable in all but the simplest of situations. And of course, it'd be nice if we only had to do this on the odd function, but like I mentioned above, tag one function noexcept and it starts to spread like a plague through your code...
This is itself is annoying, but the last problem is insidious. Unlike const, noexcept isn't checked at compile time. So while const is annoying at first, at the very least its trivial to debug. noexcept on the other hand is a nightmare, make a mistake and you don't get an easy to find compiler error pointing directly at the error, no you get some weird seg fault or stack corruption in some bizarre part of code... Multiply this over an entire code base... and well...
/sigh
Now noexcept COULD be very good, something like it is very useful. If noexcept was checked at compile time and the specifier was only used as a declaration (ie. you didn't need to specify noexcept for functions under normal circumstances, instead the compiler deduced it from static code analysis, and noexcept was only required when needed to override the default analysis, or in function pointer declarations, etc...) then it could be very useful. But of course that doesn't work on 60000 year old machines running on 93 bit architectures with 4kb of ram that have no way to perform cross translation unit analysis. So instead we get this half baked monstrosity.
For anyone who's gotten this far. My suggestion would be to only use noexcept on move constructor/move operator, and otherwise forget it exists.
This is a warning for those who might wish to travel down the noexcept rabbit hole, there is nothing but darkness and insanity waiting for you...