Difference Between C++03 Throw() Specifier C++11 Noexcept

Difference between C++03 throw() specifier C++11 noexcept

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().

Is there any difference between noexcept and empty throw specification for an lambda expression?

Is there any difference between noexcept and empty throw specification...?

Yes there is.

The first difference that comes to mind is what happens if an exception is thrown?

  • In the case of throw(), std::unexpected() is called. The default handler for unexpected will call terminate.
  • In the case of noexcept, std::terminate() is called.

The second is that the dynamic exception specification is deprecated.

Deprecates

noexcept is an improved version of throw(), which is deprecated in C++11. Unlike throw(), noexcept will not call std::unexpected and may or may not unwind the stack, which potentially allows the compiler to implement noexcept without the runtime overhead of throw().


Is there a convincible reason, why should I mark such expression (or similar basic expresions) with either modifiers...?

It is an expression of intent. If you intend that the lambda never throws, and if it does it is deemed fatal to the execution of the program, then yes - you should mark the lambda as noexcept (throw() is deprecated).

How to use noexcept in C++ or How does it work?

A noexcept specification on a function is merely a method for a programmer to inform the compiler whether or not a function should throw exceptions.

The compiler can use this information to enable certain optimizations on non-throwing functions as well as enable the noexcept operator, which can check at compile time if a particular expression is declared to throw any exceptions.

For example, containers such as std::vector will move their elements if the elements' move constructor is noexcept, and copy otherwise (unless the copy constructor is not accessible, but a potentially throwing move constructor is, in which case the strong exception guarantee is waived).

noexcept is an improved version of throw(), which is deprecated in C++11. Unlike throw(), noexcept will not call std::unexpected and may or may not unwind the stack, which potentially allows the compiler to implement noexcept without the runtime overhead of throw().

For more details, please visit below websites

  • https://akrzemi1.wordpress.com/2014/04/24/noexcept-what-for/
  • When should I really use noexcept?

Edit: Sample source code to illustrate above points.

// whether foo is declared noexcept depends on if the expression
// T() will throw any exceptions, check in compile time
template <class T>
void foo() noexcept(noexcept(T())) {
}

void bar() noexcept(true) {
}

void baz() noexcept {
throw 42;
} // noexcept is the same as noexcept(true)

int main()
{
foo<int>(); // noexcept(noexcept(int())) => noexcept(true), so this is fine

bar(); // fine
baz(); // compiles, but at runtime this calls std::terminate
}

C++ omitting `noexcept` specifier versus `noexcept(false)`, what is their precise meaning?

By specifying noexcept(true), you claim that the function never throws exceptions. By specifying noexcept(false), or not specifying anything, you do not claim that the function never throws exceptions.

So it's basically your statement (2), but note that for the compiler, that's equivalent to your statement (1). If the compiler is not assured that the function will not throw, it must assume that it can.

The relevant bit of the standard is C++11 15.4/12:

A function with no exception-specification or with an exception-specification of the form noexcept(constant-expression) where the constant-expression yields false allows all exceptions. An exception-specification is
non-throwing if it is of the form throw(), noexcept, or noexcept(constant-expression) where the constant-expression
yields true. A function with a non-throwing exception-specification does not allow any exceptions.

There are only two deviations from that rule. One is destructors—putting no exception specification on a destructor gives the destructor the same exception specification as the default-generated one would have. That is, noexcept(true) if and only if all functions which would be directly invoked from the default-generated destructor are noexcept(true).

The other one are deallocation functions (operator delete)—a deallocation function without an explicit exception specification is treated as noexcept(true).

When should I really use noexcept?

I think it is too early to give a "best practices" answer for this as there hasn't been enough time to use it in practice. If this was asked about throw specifiers right after they came out then the answers would be very different to now.

Having to think about whether or not I need to append noexcept after every function declaration would greatly reduce programmer productivity (and frankly, would be a pain).

Well, then use it when it's obvious that the function will never throw.

When can I realistically expect to observe a performance improvement after using noexcept? [...] Personally, I care about noexcept because of the increased freedom provided to the compiler to safely apply certain kinds of optimizations.

It seems like the biggest optimization gains are from user optimizations, not compiler ones due to the possibility of checking noexcept and overloading on it. Most compilers follow a no-penalty-if-you-don't-throw exception handling method, so I doubt it would change much (or anything) on the machine code level of your code, although perhaps reduce the binary size by removing the handling code.

Using noexcept in the big four (constructors, assignment, not destructors as they're already noexcept) will likely cause the best improvements as noexcept checks are 'common' in template code such as in std containers. For instance, std::vector won't use your class's move unless it's marked noexcept (or the compiler can deduce it otherwise).

Why don't throw() and noexcept have any overhead?

gcc and clang have very similar code generation as they are largely ABI compatible with one another. I only have clang to answer your question with, but my answer should apply to your gcc compiler fairly closely.

One can disassemble throw_func, noexcept_func and std_func using the -S command line flag. Upon doing so, you will note that the three functions all generate remarkably similar assembly.

Differences include:

  1. The mangled name of the functions will differ: __Z10throw_funcv, __Z13noexcept_funcv, and __Z8std_funcv.

  2. The "normal path" assembly code will be identical for all three functions except perhaps for the names of labels.

  3. throw_func and noexcept_func will generate "exception tables" after the code. These tables instruct the low-level C++ runtime library how to unwind the stack. This includes instructions on what destructors must be run, what catch blocks to try, and in the case of these two functions, what to do if an exception tries to propagate out. throw_func will contain a call to ___cxa_call_unexpected and noexcept_func will contain a call to ___clang_call_terminate (for gcc that will be named something else).

  4. std_func will not contain calls to unexpected nor terminate. Nor will it have an "exception table". There are no destructors to run, no try/catch clauses to land in, and there is no need to call unexpected or terminate.

In summary, the only difference in these three functions is in the "exceptional path". And the "exceptional path" adds code size, but is never executed by your main. In real-world code, just the added code size can impact run-time performance. However for code that is executed often, and small enough to fit in cache (such as this test), the code size hit won't cause any run-time performance hit.

For completeness, here is the noexcept_func assembly. Everything below LBB0_1: is to handle the exceptional path. LBB0_1: thru Ltmp1: throws the exception. Ltmp2: is a "landing pad" that the runtime will branch to if an exception tries to unwind through here. And GCC_except_table0: is the exception table itself.

    .globl  __Z13noexcept_funcv
.align 4, 0x90
__Z13noexcept_funcv: ## @_Z13noexcept_funcv
.cfi_startproc
.cfi_personality 155, ___gxx_personality_v0
Leh_func_begin0:
.cfi_lsda 16, Lexception0
## BB#0:
pushq %rbp
Ltmp3:
.cfi_def_cfa_offset 16
Ltmp4:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp5:
.cfi_def_cfa_register %rbp
movq _val(%rip), %rax
leaq 1(%rax), %rcx
movq %rcx, _val(%rip)
testq %rax, %rax
je LBB0_1
LBB0_2:
popq %rbp
retq
LBB0_1:
movl $1, %edi
callq ___cxa_allocate_exception
Ltmp0:
movq __ZTI9exception@GOTPCREL(%rip), %rsi
xorl %edx, %edx
movq %rax, %rdi
callq ___cxa_throw
Ltmp1:
jmp LBB0_2
LBB0_3:
Ltmp2:
movq %rax, %rdi
callq ___clang_call_terminate
.cfi_endproc
Leh_func_end0:
.section __TEXT,__gcc_except_tab
.align 2
GCC_except_table0:
Lexception0:
.byte 255 ## @LPStart Encoding = omit
.byte 155 ## @TType Encoding = indirect pcrel sdata4
.asciz "\242\200\200" ## @TType base offset
.byte 3 ## Call site Encoding = udata4
.byte 26 ## Call site table length
Lset0 = Leh_func_begin0-Leh_func_begin0 ## >> Call Site 1 <<
.long Lset0
Lset1 = Ltmp0-Leh_func_begin0 ## Call between Leh_func_begin0 and Ltmp0
.long Lset1
.long 0 ## has no landing pad
.byte 0 ## On action: cleanup
Lset2 = Ltmp0-Leh_func_begin0 ## >> Call Site 2 <<
.long Lset2
Lset3 = Ltmp1-Ltmp0 ## Call between Ltmp0 and Ltmp1
.long Lset3
Lset4 = Ltmp2-Leh_func_begin0 ## jumps to Ltmp2
.long Lset4
.byte 1 ## On action: 1
.byte 1 ## >> Action Record 1 <<
## Catch TypeInfo 1
.byte 0 ## No further actions
## >> Catch TypeInfos <<
.long 0 ## TypeInfo 1
.align 2

noexcept vs Throws: nothing

In Madrid we were strongly influenced by N3279 which includes the following guidelines:

Adopted Guidelines

  • No library destructor should throw. They shall use the implicitly supplied (non- throwing) exception specification.

  • Each library function having a wide contract, that the LWG agree cannot throw, should be marked as unconditionally noexcept.

  • If a library swap function, move-constructor, or move-assignment operator is conditionally-wide (i.e. can be proven to not throw by applying the noexcept operator) then it should be marked as conditionally noexcept. No other function should use a conditional noexcept specification.

  • Library functions designed for compatibility with “C” code (such as the atomics facility), may be marked as unconditionally noexcept.

I would not interpret these guidelines as necessarily targeting a wider audience. This is mainly an admission that we do have backward compatibility concerns with adding noexcept. If we get it wrong, noexcept is easier to add than to remove in the next standard. So we attempted an application of noexcept that was both conservative and systematic.



Related Topics



Leave a reply



Submit