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.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 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) – AndyG Nov 13 '17 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. – Jarod42 Nov 13 '17 at 14:09
  • @AndyG: See edit. – einpoklum Nov 13 '17 at 18:08
  • @Jarod42: I'm not sure what you mean by "as if" in this context. – einpoklum Nov 13 '17 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. – Jarod42 Nov 13 '17 at 19:22
  • @Jarod42: Oh, well, great, that's basically what I meant by inferring `noexcept` (except that it only happens when optimizations are enabled). Right? – einpoklum Nov 13 '17 at 19:33

1 Answers1

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.

AndyG
  • 39,700
  • 8
  • 109
  • 143
  • the point for constructors applies to implicitly declared or explicitly defaulted ones only. https://godbolt.org/g/MW54Ah I suspect it's the same for assignment ops – bolov Nov 13 '17 at 14:48
  • @bolov: That is the point of *"is defaulted on its first declaration"*. – Jarod42 Nov 13 '17 at 15:14
  • 1
    So, you're saying that `int foo() { return 1; }` is _not_ assumed to be `noexcept`? Really? – einpoklum Nov 13 '17 at 18:05
  • 1
    @einpoklum: That's exactly what I'm saying, unfortunately. [Demo](https://wandbox.org/permlink/nwz5zeNaCGoJEc0q) – AndyG Nov 13 '17 at 18:15