Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Usage of "noexcept"

57 views
Skip to first unread message

bitrex

unread,
Mar 15, 2017, 12:07:04 PM3/15/17
to
I'm a little confused on how to properly use the "noexcept" keyword. I
recall reading a blog entry a while back saying that it wasn't
particularly useful, except in the circumstance on certain constructors
and assignment operators to indicate to certain STL containers that the
structures would not throw, which could speed some operations, but I
don't recall the details.

If anyone could elaborate I'd appreciate it...

Scott Lurndal

unread,
Mar 15, 2017, 12:28:37 PM3/15/17
to
from http://en.cppreference.com/w/cpp/language/noexcept_spec

"Note that a noexcept specification on a function is not a compile-time
check; it 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)."

Öö Tiib

unread,
Mar 16, 2017, 2:39:57 PM3/16/17
to
The effect of noexcept is typically quite small and it does not help to
find defects faster (unlike for example constexpr) so I use it only when
optimizing for speed. I optimize for speed only in late stage of project
and that affects only small subset of code base.

When I use it I basically specify everything that shows up in profile
but can't possibly throw as noexcept and that is it.

Bonita Montero

unread,
Mar 16, 2017, 2:49:25 PM3/16/17
to
> I'm a little confused on how to properly use the "noexcept" keyword.
> I recall reading a blog entry a while back saying that it wasn't
> particularly useful, except in the circumstance on certain constructors
> and assignment operators to indicate to certain STL containers that the
> structures would not throw, which could speed some operations, but I
> don't recall the details.

noexcept could theoretically help compilers to optimize the tables used
with table-driven exception-handling. This means, that for each point
where a noexcept-function is called, the compiler wouldn't have to
create a handler-code or table-entry for exceptions bubbling through
the call-stack for this call.

--
http://facebook.com/bonita.montero/

Bonita Montero

unread,
Mar 16, 2017, 3:05:20 PM3/16/17
to
> noexcept could theoretically help compilers ...

That doesn't seem to be only theory.
The following code crashes if you uncomment noexcept
with Visual C++ 2017 on Windows and g++ on Linux.

void f2()
{
throw int( 123 );
}

void f1() // noexcept
{
f2();
}


int main()
{
try
{
f1();
}
catch( int )
{
}
}



--
http://facebook.com/bonita.montero/

peter koch

unread,
Mar 16, 2017, 3:20:02 PM3/16/17
to
Den torsdag den 16. marts 2017 kl. 20.05.20 UTC+1 skrev Bonita Montero:
> > noexcept could theoretically help compilers ...
>
> That doesn't seem to be only theory.
> The following code crashes if you uncomment noexcept
> with Visual C++ 2017 on Windows and g++ on Linux.
>
> void f2()
> {
> throw int( 123 );
> }
>
> void f1() // noexcept
> {
> f2();
> }
>
>
> int main()
> {
> try
> {
> f1();
> }
> catch( int )
> {
> }
> }

"Crashes"? No. The program is terminated - as it should be.

peter koch

unread,
Mar 16, 2017, 3:25:08 PM3/16/17
to
Read the documentation - see eg. cppreference.com.
nothrow could give significant performance improvements, in particular on move constructors when operating on containers. As an example, moving elements in a std::vector becomes much faster if its elements are cheap to move compared to assign and the move constructors are nothrow.

Bonita Montero

unread,
Mar 16, 2017, 3:32:58 PM3/16/17
to
> "Crashes"? No. The program is terminated - as it should be.

I tried it with Windows Services for Linux, i.e. the Linux-environment
for Windows, and g++ 4.8.4. With this environment I get a core-dump.
And with Visual C++ 2017 the program also crashes when I run the
release-build; the debug-build shows that abort() is called.

--
http://facebook.com/bonita.montero/

Alf P. Steinbach

unread,
Mar 16, 2017, 4:03:40 PM3/16/17
to
On 16-Mar-17 8:32 PM, Bonita Montero wrote:
>> "Crashes"? No. The program is terminated - as it should be.
>
> I tried it with Windows Services for Linux, i.e. the Linux-environment
> for Windows, and g++ 4.8.4. With this environment I get a core-dump.
> And with Visual C++ 2017 the program also crashes when I run the
> release-build; the debug-build shows that abort() is called.

The standard requires that `std::terminate` is called. I wasn't aware
that Visual C++ implemented this, thanks for testing. It did not
implement the general mechanism for C++03 throw specifications.

<url: http://en.cppreference.com/w/cpp/language/noexcept_spec>

The behavior of `std::terminate` can be modified by installing a
terminate handler. The default handler just calls `abort()`.

`abort` in turn raises the SIGABRT signal.

Handling that signal is a lower level way to modify the behavior.

However, in C++ a signal handler can't do just about anything without
getting into Undefined Behavior, and for a hosted environment I can't
think of any useful modification at that low level.


Cheers!,

- Alf

Ian Collins

unread,
Mar 16, 2017, 6:37:13 PM3/16/17
to
On 03/17/17 08:32 AM, Bonita Montero wrote:
>> "Crashes"? No. The program is terminated - as it should be.
>
> I tried it with Windows Services for Linux, i.e. the Linux-environment
> for Windows, and g++ 4.8.4. With this environment I get a core-dump.
> And with Visual C++ 2017 the program also crashes when I run the
> release-build; the debug-build shows that abort() is called.

Could this be a platform run time bug?

When I try your code on Linux or Solaris at any optimisation level I get
the correct result:

clang++ -std=c++14 -O2 /tmp/x.cc; ./a.out
terminate called after throwing an instance of 'int'
Aborted (core dumped)

--
Ian

peter koch

unread,
Mar 16, 2017, 6:40:34 PM3/16/17
to
To me it looks as if you get the same (correct) result as Bonita.

/Peter

Ian Collins

unread,
Mar 16, 2017, 7:09:12 PM3/16/17
to
release-build; the debug-build shows that abort() is called." suggested
otherwise!

--
Ian

Manfred

unread,
Mar 16, 2017, 9:23:21 PM3/16/17
to
On 3/16/2017 8:25 PM, peter koch wrote:
> Den onsdag den 15. marts 2017 kl. 17.07.04 UTC+1 skrev bitrex:
<snip>
>> If anyone could elaborate I'd appreciate it...
>
> Read the documentation - see eg. cppreference.com.
> nothrow could give significant performance improvements, in particular on move constructors when operating on containers. As an example, moving elements in a std::vector becomes much faster if its elements are cheap to move compared to assign and the move constructors are nothrow.
>
True, but I would note that in the case of move constructors this is not
only a performance issue.
When, thanks to noexcept, a move constructor is called instead of a copy
constructor, this is also a change in semantics.

Paavo Helde

unread,
Mar 17, 2017, 10:46:03 AM3/17/17
to
On 17.03.2017 3:23, Manfred wrote:
>>
> True, but I would note that in the case of move constructors this is not
> only a performance issue.
> When, thanks to noexcept, a move constructor is called instead of a copy
> constructor, this is also a change in semantics.

There is a special clause in the standard (12.8/31) allowing the
compiler to elide any copy and move constructors, even if they have side
effects. Any program whose semantics depend on these things called or
not called is thus extremely fragile.

Alf P. Steinbach

unread,
Mar 17, 2017, 12:00:00 PM3/17/17
to
I think you misunderstand.

Manfred is not talking about the usual elision but about the
`std::vector`'s choice about what to call.

In short, the committee didn't have the guts to require move
constructors to be no-throw, and instead chose to make std::vector
unreliable, decidedly non-exception-safe in a certain case:

C++14 §23.3.6.3/3 about `reserve()`
“If an exception is thrown other than by the move constructor of a
non-CopyInsertable type, there are no effects”

Hidden in that innocuous wording, if an exception /is/ thrown from the
move constructor of a non-CopyInsertable type, then all bets are off.

To avoid this problem for a CopyInsertable type with possibly throwing
move constructor, a std::vector must copy items from its old buffer to
its new buffer, instead of moving. If an exception is thrown during
copying the old clean vector state can be reinstated (strong exception
guarantee). The quoted sentence guarantees this.

Thus it's not about a implementation-dependent optimization, but about
guaranteed, dependenable behavior, related to some dirtyness.


Cheers & hth.,

- Alf

Paavo Helde

unread,
Mar 17, 2017, 3:21:17 PM3/17/17
to
On 17.03.2017 17:59, Alf P. Steinbach wrote:
> On 17-Mar-17 3:45 PM, Paavo Helde wrote:
>> On 17.03.2017 3:23, Manfred wrote:
>>>>
>>> True, but I would note that in the case of move constructors this is not
>>> only a performance issue.
>>> When, thanks to noexcept, a move constructor is called instead of a copy
>>> constructor, this is also a change in semantics.
>>
>> There is a special clause in the standard (12.8/31) allowing the
>> compiler to elide any copy and move constructors, even if they have side
>> effects. Any program whose semantics depend on these things called or
>> not called is thus extremely fragile.
>
> I think you misunderstand.
>
> Manfred is not talking about the usual elision but about the
> `std::vector`'s choice about what to call.

I just wanted to stress than for a sanely written program there would be
no difference (other than performance-wise, potentially) what
std::vector decides to call or not to call when resizing the buffer.

Maybe I should expand my opinion a bit more: any program whose semantics
depend on the copy or move constructors called or not called, or having
exception-throwing move constructors or destructors, is extremely fragile.


Manfred

unread,
Mar 18, 2017, 12:15:59 PM3/18/17
to
On 3/17/2017 8:21 PM, Paavo Helde wrote:
> On 17.03.2017 17:59, Alf P. Steinbach wrote:
>> On 17-Mar-17 3:45 PM, Paavo Helde wrote:
>>> On 17.03.2017 3:23, Manfred wrote:
>>>>>
>>>> True, but I would note that in the case of move constructors this is
>>>> not
>>>> only a performance issue.
>>>> When, thanks to noexcept, a move constructor is called instead of a
>>>> copy
>>>> constructor, this is also a change in semantics.
>>>
>>> There is a special clause in the standard (12.8/31) allowing the
>>> compiler to elide any copy and move constructors, even if they have side
>>> effects. Any program whose semantics depend on these things called or
>>> not called is thus extremely fragile.
>>
>> I think you misunderstand.
>>
>> Manfred is not talking about the usual elision but about the
>> `std::vector`'s choice about what to call.
Indeed
>
> I just wanted to stress than for a sanely written program there would be
> no difference (other than performance-wise, potentially) what
> std::vector decides to call or not to call when resizing the buffer.
Agreed. Only I would say that for a /well written/ program there would
be no difference. (I would agree that code that would be affected by
such difference would be bad - I wouldn't go as far as /insane/)

>
> Maybe I should expand my opinion a bit more: any program whose semantics
> depend on the copy or move constructors called or not called, or having
> exception-throwing move constructors or destructors, is extremely fragile.
>
I would agree that code that /depends/ on the difference in semantics
between copy and move is fragile, but still there /is/ a difference
between them.
Coming back to the original issue, I think that it is reductive to
classify "noexcept" as a matter of optimization:
if you use 'inline', or switch between -O0 and -O2 you can rely on the
fact that legal code will behave identically, except possibly for
runtime performance;
if you use 'noexcept' you are actually changing the behaviour of code.
0 new messages