Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can the "main" function be declared with the "noexcept" specifier?

Is the following code valid in C++?

int main() noexcept { } 

Both clang++ 3.8.0 and g++ 7.2.0 compile it fine (with -std=c++14 -O0 -Wall -Wextra -Werror -pedantic-errors compilation flags).

Is it allowed to use complex conditions (e.g. including noexcept operator) in the noexcept specification of the main function?

And what about C++17? As I know noexcept specifier becomes the part of the function type in this revision of the standard.

like image 580
Constructor Avatar asked Nov 30 '17 22:11

Constructor


People also ask

Can be declared Noexcept?

"Function can be declared 'noexcept'." If code is not supposed to cause any exceptions, it should be marked as such by using the 'noexcept' specifier. This would help to simplify error handling on the client code side, as well as enable compiler to do additional optimizations.

What is Noexcept used for 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.

What does it mean to specify a function as Noexcept false?

In contrast, noexcept(false) means that the function may throw an exception. The noexcept specification is part of the function type but can not be used for function overloading. There are two good reasons for the use of noexcept: First, an exception specifier documents the behaviour of the function.

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.


1 Answers

The standard [[basic.start.main]] specifies the following constraints on the main function:

An implementation shall allow both:

— a function of () returning int and

— a function of (int, pointer to pointer to char) returning int

Moreover:

A program that defines main as deleted or that declares main to be inline, static, or constexpr is ill-formed.

In practice, there is no specification about noexcept qualifier for main. On the other hands, noexcept is allowed as a specifier for whatever function. That would imply main noexcept is not ill-formed.


What's difference w/o noexcept main?

Since the standard is not very explicit about noexcept for main function as we've seen, we can try to deduct some behaviour and check the implementations.

From here:

Whenever an exception is thrown and the search for a handler encounters the outermost block of a non-throwing function, the function std::terminate is called.

While the general rule for exceptions, from here:

If an exception is thrown and not caught, including exceptions that escape the initial function of std::thread, the main function, and the constructor or destructor of any static or thread-local objects, then std::terminate is called. It is implementation-defined whether any stack unwinding takes place for uncaught exceptions.

This implies that throw from main function always generates a std::terminate invocation. Regardless of noexcept specification of the main.

Implementation side:

Indeed, the following codes:

int main(int argc, char* argvp[]) {   throw 1;   return 0; } 

and

int main(int argc, char* argvp[]) noexcept {   throw 1;   return 0; } 

will produce the same output assembly. For example in GCC:

main:         movl    $4, %edi         subq    $8, %rsp         call    __cxa_allocate_exception         xorl    %edx, %edx         movl    $1, (%rax)         movl    typeinfo for int, %esi         movq    %rax, %rdi         call    __cxa_throw 

That means it will be resolved into an invocation of std::terminate because the stack frame is empty at "main level" regardless of noexcept specification.

like image 178
BiagioF Avatar answered Sep 21 '22 09:09

BiagioF