12

Suppose a C++ compiler is compiling a function whose definition is available in the same translation unit as its invocation. Suppose that it does not throw itself nor calls a function that is know to throw. Suppose also no extern C code is called, nor a numeric division with a potentially-zero value.

Under these assumptions, will the compiler treat the function as noexcept? If not, are there additional conditions under which noexcept is inferred?

Specifically, what about super-simple functions such as

void foo() { } /* this one */ class A { int x_; public: x() const { return x_; } /* ... and this one */ } 

?

I'd like an answer based only on the standard, foremost, and possibly also what GCC and clang do.

6
  • IIRC it only infers noexcept for a few special member functions. e.g. destructors unless you specify otherwise. (Will check the standard and get back on this) Commented Nov 13, 2017 at 14:05
  • For optimization, compiler has to follow as-if rule. From standard point of view, I don't think that compiler can change noexcept of a function. Commented Nov 13, 2017 at 14:09
  • @AndyG: See edit. Commented Nov 13, 2017 at 18:08
  • @Jarod42: I'm not sure what you mean by "as if" in this context. Commented Nov 13, 2017 at 18:09
  • I mean that if compiler can know that no exceptions can occur, it can avoid to generate code to handle exception for that part. Commented Nov 13, 2017 at 19:22

1 Answer 1

6

Almost all functions are assumed to be potentially throwing unless you explicitly use a noexcept specifier. The exceptions are for your own definitions of delete (deallocation functions), and some special member functions: constructors, destructors, and assignment operators. (C++17)

From [except.spec]

If a declaration of a function does not have a noexcept-specifier, the declaration has a potentially throwing exception specification unless it is a destructor or a deallocation function or is defaulted on its first declaration, in which cases the exception specification is as specified below and no other declaration for that function shall have a noexcept-specifier.

Constructors

Are implicitly noexcept unless any initialization performed for any member (or a member's member etc) is potentially throwing

Destructors

Are implicitly noexcept unless any destructor for a potentially constructed sub-object is potentially throwing.

Assignment operators

Are implicitly noexcept unless any use of assignment within is potentially-throwing.


Here's some sample code that demonstrates the above (clang 6.0.0, gcc 8.0.0):

int foo() { return 1; } int bar() noexcept{ return 1; } struct Foo{}; struct Bar{ Bar(){} }; int main() { static_assert(noexcept(bar())); static_assert(!noexcept(foo())); static_assert(noexcept(Foo())); static_assert(noexcept(Foo().~Foo())); static_assert(noexcept(Foo().operator=(Foo()))); static_assert(!noexcept(Bar())); Bar b; static_assert(noexcept(b.~Bar())); } 

Yet another reason to use =default or allow the compiler to generate its own versions of your special member functions via omission.

Sign up to request clarification or add additional context in comments.

4 Comments

the point for constructors applies to implicitly declared or explicitly defaulted ones only. godbolt.org/g/MW54Ah I suspect it's the same for assignment ops
@bolov: That is the point of "is defaulted on its first declaration".
So, you're saying that int foo() { return 1; } is not assumed to be noexcept? Really?
@einpoklum: That's exactly what I'm saying, unfortunately. Demo

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.