[Development] Proposal: adding Q_DECL_NOEXCEPT to many methods
Marc Mutz
marc.mutz at kdab.com
Fri Aug 3 00:25:04 CEST 2012
Hi Thiago,
On Thursday August 2 2012, Thiago Macieira wrote:
> The benefits are:
> - callers do not need to emit exception handlers around such functions
> - the compiler may assume that no exception unexpectedly happens inside
> that function body, foregoing exception handlers inside it as well.
AFAIU, the compiler needs to make sure that std::terminate is called if an
unexpected exception is thrown, which would require the equivalent of a
function-try-catch block where the catch block calls std::terminate().
Do you have a reference?
> The first behaviour is present with a C++03's empty exception specification
> (i.e., throw() in the function declaration),
AFAIU, that's only true for MSVC, and counter to what C++03 actually mandated.
> but the second behaviour is
> new in C++11. In the previous standard, the compiler was forced to emit
> exception code for the case when exceptions did happen even when they
> shouldn't. For that reason, the C++03 exception specification is
> deprecated.
Ok, here I'm with you again.
Btw, I've done some very rough tests:
What I set out to check was whether calling non-noexcept functions from
noexcept ones incurs a penalty for the std::terminate call that is required
if a noexcept function would leak an exception (it can't, it must invoke
std::terminate() instead, and the GCC compilate works as expected in that
respect, when I make foo() below throw) vs. if the compiler can prove that
all operations are noexcept.
What I found was that a declaration
int foo() noexcept;
vs.
int foo();
doesn't influence the assembly at all (expected, the exception must be
swallowed inside foo(), not, as with throw() by the caller of foo()).
But
int foo();
int bar() noexcept { const int f = foo(); return 2*f;}
seems to introduce a new entry in the gcc_except_table (that's expected, too.
bar() needs to be prepared for foo() to throw and call std::terminate() in
response) whereas
int foo() noexcept;
int bar() noexcept { const int f = foo(); return 2*f; }
does not (also expected, as the compile can now prove that the body of bar()
can't throw; the responsibility of preventing exceptions from exiting foo()
is now with foo()'s implementation).
The function itself is unchanged, though. I don't know enough compiler
internals to properly interpret this result :)
In a similar test,
int foo();
int bar() noexcept { const int f = foo(); return 2*f; }
also adds an entry to the exception table, compared to
int foo();
int bar() { const int f = foo(); return 2*f; }
which doesn't. What's more interesting is that I get with -m64 -O2 and no -g
an .o size difference of 1360 bytes for the second vs. 1576 for the first
variant. This size difference is much bigger than I would have expected from
the .s-file diff. For comparision, the size for both bar() and foo() noexcept
is also 1360.
If there really is a 200 byte overhead per nonexcept function calling
non-noexcept functions, we'd need to avoid marking functions noexcept that,
say, Q_ASSERT(), e.g., even though we could probably live with the
std::terminate that's called if Q_ASSERT() throws (at that point, it's clear
that the assertion failed, if not from the resulting backtrace) :)
Even if it isn't a full 200 bytes overhead, we should make qt_assert()
noexcept before putting it on, say, QMutex::lock() which calls it.
Thanks,
Marc
--
Marc Mutz <marc.mutz at kdab.com> | Senior Software Engineer
KDAB (Deutschland) GmbH & Co.KG, a KDAB Group Company
www.kdab.com || Germany +49-30-521325470 || Sweden (HQ) +46-563-540090
KDAB - Qt Experts - Platform-Independent Software Solutions
More information about the Development
mailing list