Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In what cases does a C++ compiler infer noexcept?

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.

like image 826
einpoklum Avatar asked Nov 13 '17 14:11

einpoklum


People also ask

What is Noexcept in C?

The noexcept operator performs a compile-time check that returns true if an expression is declared to not throw any exceptions. It can be used within a function template's noexcept specifier to declare that the function will throw exceptions for some types but not others.

Is Noexcept required?

Explicit instantiations may use the noexcept specifier, but it is not required. If used, the exception specification must be the same as for all other declarations.

What happens when Noexcept throws?

If you throw, your program terminates What happens if you throw from a noexcept function? Your program terminates, and may or may not unwind the stack. Terminating program isn't the nicest way to report an error to your user. You would be surprised that most of C++ code might throw.

What is noexcept in C++ with example?

noexcept operator. (since C++11) The noexcept operator performs a compile-time check that returns true if an expression is declared to not throw any exceptions. It can be used within a function template's noexcept specifier to declare that the function will throw exceptions for some types but not others.

What happens when an exception is thrown from a noexcept function?

When an exception is thrown from a function that is declared noexcept or noexcept(true), std::terminate is invoked. When an exception is thrown from a function declared as throw() in /std:c++14 mode, the result is undefined behavior.

Can a template function that copies its argument be declared noexcept?

A template function that copies its argument might be declared noexcept on the condition that the object being copied is a plain old data type (POD). Such a function could be declared like this:

What is the difference between inner noexcept and outer noexcept?

The inner noexcept ist the noexcept operator and the outer the noexcept specifier. The expression noexcept (T (src)) checks in this case if the copy constructor is non-throwing. This is the case for the class Noexcept (2) but not for the class NonNoexcept (3) b ecause of the copy constructor of std::vector that may throw.


1 Answers

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.

like image 110
AndyG Avatar answered Oct 19 '22 07:10

AndyG