[Development] Proposal: adding Q_DECL_NOEXCEPT to many methods

Thiago Macieira thiago.macieira at intel.com
Fri Aug 3 00:44:01 CEST 2012


On sexta-feira, 3 de agosto de 2012, às 00.25.04, you wrote:
> 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?

Looking at the code generated by GCC, it looks like it generates no extra 
*code*, but it does generate a block of exception data. It indicates probably 
that no exceptions are expected in that block and that the stack unwinder 
should do what it must on its own.

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

That's the difference in behaviour, the flaw in the original standard.

> 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

Yep.

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

Yep.

Which is why we should use noexcept only when we can prove that it doesn't 
throw. Most of glibc does declare its functions as nothrow, even in C mode. 
The keyword says no exceptions will leak. If, in addition, the compiler can 
prove that none can be produced, it doesn't need to write the exception table.

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

Because no unwinding is necessary. Now try adding a type with a destructor 
before the call to foo() and you'll see something quite different.

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

You can't compare the size in .o since it contains relocation information that 
will be removed by the linker.

> 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) :)

I don't think it's 200 bytes, but there is an overhead. An overhead, mind you, 
that is read-only, sharable and clean (no relocations). The exception tables 
are usually pretty far from the text, which means the pages containing them 
are often not demand-paged into memory at all. It makes the library size 
bigger, but shouldn't affect much at runtime.

That said, you're right: we should make our noexcept functions call only other 
noexcept functions.

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

Agreed. It's already noreturn on non-Windows, noexcept makes sense. Even if it 
*can* throw, it makes no sense for qt_assert to throw and cause a stack 
unwinding, thereby permitting code to continue executing after a double fault 
(assertion and exception).

-- 
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
   Software Architect - Intel Open Source Technology Center
      PGP/GPG: 0x6EF45358; fingerprint:
      E067 918B B660 DBD1 105C  966C 33F5 F005 6EF4 5358
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 190 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.qt-project.org/pipermail/development/attachments/20120803/0d5f475e/attachment.sig>


More information about the Development mailing list