16

According to the C++ standard, are implementations of the C++ standard library allowed to strengthen noexcept specifications of methods and other functions of the C++ standard library as defined by the standard?

For example, if the C++ standard specifies some function std::f as void f(); are standard library implementations allowed to implement it as void f() noexcept; instead?

jotik
  • 17,044
  • 13
  • 58
  • 123
  • all implementations remove exception handling code when they can prove that an exception will not happen. the `noexcept` keyword is more about what to do if someone down the call stack lied to the compiler. – Richard Hodges Jun 27 '16 at 10:35
  • @RichardHodges To me, `noexcept` is just a function contract that can be checked inside the code. The concept of "non-throwing" functions has always existed, but now we can verify it in our code if we want to make some "exception unsafe but faster" code. The low-level code generation is pretty much irrelevant to me. – KABoissonneault Jun 27 '16 at 13:41
  • 1
    @KABoissonneault i think we're saying the same thing - and you're saying it better than me :) – Richard Hodges Jun 27 '16 at 15:01

1 Answers1

12

The Standard says yes:

§ 17.6.5.12.1 Restrictions on exception handling [res.on.exception.handling]

  1. Any of the functions defined in the C++ standard library can report a failure by throwing an exception of a type described in its Throws: paragraph. An implementation may strengthen the exception specification for a non-virtual function by adding a non-throwing noexcept-specification.

[...]

  1. Destructor operations defined in the C++ standard library shall not throw exceptions. Every destructor in the C++ standard library shall behave as if it had a non-throwing exception specification. Any other functions defined in the C++ standard library that do not have an exception-specification may throw implementation-defined exceptions unless otherwise specified. An implementation may strengthen this implicit exception-specification by adding an explicit one.

(Comma 4 seems to just allow to be explicit about the exception specification, and to warn that the lack of an explicit exception specification means that the implementation is allowed to throw anything).


To be honest, I don't understand why this is allowed and adding constexpr is not (§ 17.6.5.6). They look like the two sides of the same medal -- by using type traits and SFINAE you can have code which shows different behaviours depending on which Standard Library implementation you use (if it marks some functions as noexcept/constexpr, or if it doesn't), and that defeats the purposes of having a standard in the first place...

peppe
  • 21,934
  • 4
  • 55
  • 70
  • It's interesting that §17.6.5.6 doesn't talk about strengthening *noexcept-specification* which have *constant-expression*s. I wonder whether it is because perhaps the standard doesn't specify any of such for the standard library. – jotik Jun 27 '16 at 13:32
  • 2
    @peppe: "*To be honest, I don't understand why this is allowed and adding constexpr is not (§ 17.6.5.6).*" It's a lot easier to *accidentally* depend on `constexpr` than on `noexcept`. In the latter case, you *must* use type traits and/or SFINAE to depend on exception specifications. In the former case, all it takes is typing `constexpr float f = std::sin(32.5f);`. If that succeeds at compiling, then you have accidentally tethered your code to an implementation detail. – Nicol Bolas Jun 27 '16 at 13:46
  • @NicolBolas I would add that unlike `constexpr`, it's not exactly *wrong* to overload your code on the `noexcept`ness of the library's functions. If written properly, your generic code will still be portable: it will probably just take a different code path from one platform to another. – KABoissonneault Jun 27 '16 at 14:09
  • @NicolBolas: makes perfectly sense, but I would expect the Standard to be strict about this nonetheless. Or is there another rationale that I don't see? – peppe Jun 27 '16 at 14:10
  • @KABoissonneault: "just take a different code path" is quite a big understatement. (By the way, for the very same reason, it may just fail to compile altogether.) – peppe Jun 27 '16 at 14:12
  • @peppe I'm not sure I understand what you mean. But in case my explanation wasn't clear, let me show you a very contrived example of what I meant: http://pastebin.com/fScXhh8q. This code shouldn't fail to compile on any platform, even if one implementation defines it as `noexcept`. – KABoissonneault Jun 27 '16 at 14:23
  • 1
    @KABoissonneault: Reduced to the most simple example possible: `static_assert(noexcept(std::some::function()), "nope")`. I find it questionable if tihs compiles or not depending on the implementation, because (again, as far as I've understood) it's the same principle behind forbidding adding `constexpr`. – peppe Jun 27 '16 at 14:28
  • @peppe I think the difference here is that `constexpr` "compilation errors" can't be handled, while `noexcept` just returns a bool that can be used to make compilation fail, among other useful things. In your example, you *chose* on purpose to fail if your assertion is false. The mistake there is that you asserted something that is not always true, as stated in this answer. – KABoissonneault Jun 27 '16 at 14:32
  • @peppe: It's not uncommon to have a fast function which will work identically to a slow function (aside from execution time) when some conditions apply, but may fail completely if they don't. If there is a case in which compiler X can tell that the conditions apply but compiler Y cannot, I would suggest that having compiler X use the fast function and compiler Y use the slow one should often be preferable to having both compilers use the slow one. – supercat Jun 28 '16 at 16:13
  • @supercat: I'm not sure what do you mean by that? My point was quite simple -- implementations are not allowed to add `constexpr` to STL functions because that modifies the semantics / legality of your code. I was wondering why instead `noexcept` is allowed (as in the end that may lead to the very same sort of problems). – peppe Jun 28 '16 at 17:59
  • @peppe: Some people seem to think that given any set of source code containing templates, only one correct expansion should be considered "correct". My own view is that it's more helpful to allow for the possibility that in some cases there may be multiple correct expansions from which a compiler could select at its leisure [in which case it wouldn't matter whether some expansions were seen as valid by some compilers but others, provided that every compiler chose a valid expansion]. If from the programmer's point of view all expansions would be equally good in some circumstance, but... – supercat Jun 28 '16 at 18:13
  • ...a compiler might have reason to favor one, letting the compiler use the most favorable version could enable more useful optimizations than would be possible if the programmer had to guess. – supercat Jun 28 '16 at 18:16
  • 1
    Note, they were [originally going to allow this for constexpr](http://stackoverflow.com/a/27744080/1708801) – Shafik Yaghmour Jun 29 '16 at 05:00
  • @ShafikYaghmour: "as users may use SFINAE to observe different behavior from otherwise identical code" is exactly my point. Maybe we'll get this rule revised in the upcoming Standard editions... – peppe Jun 29 '16 at 21:14