Difference between C++03 throw() specifier C++11 noexcept
Solution 1
Exception specifiers were deprecated because exception specifiers are generally a terrible idea. noexcept
was added because it's the one reasonably useful use of an exception specifier: knowing when a function won't throw an exception. Thus it becomes a binary choice: functions that will throw and functions that won't throw.
noexcept
was added rather than just removing all throw specifiers other than throw()
because noexcept
is more powerful. noexcept
can have a parameter which compile-time resolves into a boolean. If the boolean is true, then the noexcept
sticks. If the boolean is false, then the noexcept
doesn't stick and the function may throw.
Thus, you can do something like this:
struct<typename T>
{
void CreateOtherClass() { T t{}; }
};
Does CreateOtherClass
throw exceptions? It might, if T
's default constructor can. How do we tell? Like this:
struct<typename T>
{
void CreateOtherClass() noexcept(is_nothrow_default_constructible<T>::value) { T t{}; }
};
Thus, CreateOtherClass()
will throw iff the given type's default constructor throws. This fixes one of the major problems with exception specifiers: their inability to propagate up the call stack.
You can't do this with throw()
.
Solution 2
noexcept
isn't checked at compile time.
An implementation shall not reject an expression merely because when executed it throws or might throw an exception that the containing function does not allow.
When a function that is declared noexcept
or throw()
attempts to throw an exception the only difference is that one calls terminate
and the othe calls unexpected
and the latter style of exception handling has effectively been deprecated.
Solution 3
std::unexpected()
is called by the C++ runtime when a dynamic exception specification is violated: an exception is thrown from a function whose exception specification forbids exceptions of this type.
std::unexpected()
may also be called directly from the program.
In either case, std::unexpected
calls the currently installed std::unexpected_handler
. The default std::unexpected_handler
calls std::terminate
.
Related videos on Youtube
iammilind
"Among programming languages, I am C++ ..." — BG 10.19...
Updated on April 18, 2020Comments
-
iammilind about 4 years
Is there any difference between
throw()
andnoexcept
other than being checked at runtime and compile time, respectively?This Wikipedia C++11 article suggests that the C++03 throw specifiers are deprecated.
Why so, isnoexcept
capable enough to cover all that at compile time ?[Note: I checked this question and this article, but couldn't determine the solid reason for deprecation.]
-
Fiktik over 11 yearsAccodring to this nice article also
noexcept
may incur runtime checks. The main difference between them being that breakingnoexcept
causesstd::terminate
while breakingthrow
causesstd::unexpected
. Also a slightly different stack unwinding behaviour in these cases. -
curiousguy over 4 yearsThere is nothing "compile time" checked with some exception specifications that is "runtime" checked on others. It's just a myth created by opponents of C++ exception specifications.
-
-
hmjd about 11 years+1 Useful answer, for me anyway. Still searching for an answer that says why I would want to use
noexcept
. I never usedthrow()
specifier, ever and am attempting to determine ifnoexcept
actually provides any benefit (other than compiler checked documentation). -
hmjd about 11 yearsJust found this stackoverflow.com/questions/10787766/… ...
-
Nicol Bolas about 11 years@hmjd: "Still searching for an answer that says why I would want to use noexcept." You won't find an answer to that here because that's not the question that was asked.
-
hmjd about 11 yearsYep, I know that. Was just researching
noexcept
and reading a few questions/answers on it. The most important reason I found was that some (possibly all) of the STL containers will not use the move constructor if it is not declared asnoexcept
, which I didn't realise. -
Alexander Oh over 10 yearsI wonder what happened to the case, that destructors shall not call functions that throw exceptions.
-
Nicol Bolas over 10 years@Alex: It's fine for destructors to call throwing functions. They just can't allow those exceptions to escape the destructor call.
-
Alexander Oh over 10 years@NicolBolas agree. but if noexcept would be a guarantee, the compiler could check whether a function may throw or not in a destructor. Thus being able to warn a programmer that a function is noexcept or not.
-
Nicol Bolas over 10 years@Alex:
noexcept
is a guarantee. If an exception tries to leave any function that isnoexcept
, thenstd::terminate
will be called. -
Alexander Oh over 10 years@NicolBolas the runtime calls
std::terminate
. which is WAY WORSE! code can sneak into releases that have functions markednoexcept
and at runtime (meaning at customer sites) violations are detected. I meant the compiler guarantees to generate code that doesn't throw exceptions in the first place. -
Nicol Bolas over 10 years@Alex: C++ is not a safe language. It is always the responsibility of the programmer to ensure the integrity of a C++ program. The same goes here: you are allowed to call functions that aren't marked
noexcept
. The language trusts that you will either call these functions in such a way that they will not throw, or that you will call these function in such a way that you will catch any exceptions they throw. There is no reason to force C++ programmers to only restrict themselves to functions explicitly labelednoexcept
. That would break tons of code. -
Alexander Oh over 10 years
-
Martin York over 10 years@NicolBolas: One other difference worth noting. If a function is marked
throws()
then if an exception is thrown the stack must be unwound upto the scope of that function (so all automatic variables in the function are destroyed) at which pointterminate()
is called (viaunexpected()
). If a function is markednoexcept
then if an exception is thrown then terminate is called (the unwinding of the stack is implementation defined detail). -
curiousguy over 4 years@MartinYork A difference in semantics that is irrelevant to the calling code.
-
curiousguy over 4 years@hmjd "The most important reason I found was that some (possibly all) of the STL containers will not use the move constructor if it is not declared as noexcept" Yes and changing the function decoration from
throw()
tonoexcept
was not needed to do that. -
curiousguy over 4 years"Exception specifiers were deprecated because exception specifiers are generally a terrible idea." Then the new style is equally "terrible" as the exact same critics apply, except the less useful "throw some exceptions" have been removed (which was never part of the central argument against old style spec)
-
Nicol Bolas over 4 years@curiousguy: You know, there were several sentences after the first one. Indeed, the very next sentence addresses this exact point. It's almost like I was going somewhere with that. Hence the use of qualifiers like "generally" and so forth.
-
curiousguy over 4 years@NicolBolas They were found to be of little use, but their bad reputation is similar to the bad rep of MI in many languages, it's based on completely irrelevant or bogus claims, bad example, bad understanding... Bad understanding is fixed by better explanations, not changing language syntax and semantics. I'm not saying that the full power of old throw spec was worth keeping given the (relatively extremely small) additional language and impl complexity they caused, but denigration of a tool is bad and awful when it propages deep misunderstanding of programming.
-
curiousguy over 4 yearsBut if a virtual function has
throw()
/noexcept
, compile time checking ensure that an overrider also has.