A program shall contain a global function called main.
Executing a program starts a main thread of execution ([intro.multithread], [thread.threads])
in which the main function is invoked,
and in which variables of static storage duration
might be initialized ([basic.start.static]) and destroyed ([basic.start.term]).
It is implementation-defined
whether a program in a freestanding environment is required to define a main
function. [ Note: In a freestanding environment, start-up and termination is
implementation-defined; start-up contains the
execution of constructors for objects of namespace scope with static storage duration;
termination contains the execution of destructors for objects with static storage
duration. — end note ]
An implementation shall not predefine the main function. This
function shall not be overloaded. Its type shall have C++ language linkage
and it shall have a declared return type of type
int, but otherwise its type is implementation-defined.
An implementation shall allow both
as the type of main ([dcl.fct]).
In the latter form, for purposes of exposition, the first function
parameter is called argc and the second function parameter is
called argv, where argc shall be the number of
arguments passed to the program from the environment in which the
program is run. If
argc is nonzero these arguments shall be supplied in
argv[0] through argv[argc-1] as pointers to the initial
characters of null-terminated multibyte strings (ntmbs
s) ([multibyte.strings]) and argv[0] shall be the pointer to
the initial character of a ntmbs that represents the name used to
invoke the program or "". The value of argc shall be
non-negative. The value of argv[argc] shall be 0. [ Note: It
is recommended that any further (optional) parameters be added after
argv. — end note ]
The function main shall not be used within
a program.
The linkage of main is
implementation-defined. A program that defines main as
deleted or that declares main to be
inline, static, or constexpr is ill-formed.
The main function shall not be declared with a
linkage-specification. A program that
declares a variable main at global scope or that declares the name
main with C language linkage (in any namespace) is ill-formed.
The name main is
not otherwise reserved. [ Example: Member functions, classes, and
enumerations can be called main, as can entities in other
namespaces. — end example ]
Terminating the program
without leaving the current block (e.g., by calling the function
std::exit(int)) does not destroy any
objects with automatic storage duration ([class.dtor]). If
std::exit is called to end a program during the destruction of
an object with static or thread storage duration, the program has undefined
behavior.
A return statement in main has the effect of leaving the main
function (destroying any objects with automatic storage duration) and
calling std::exit with the return value as the argument.
If control flows off the end of
the compound-statement of main,
the effect is equivalent to a return with operand 0
(see also [except.handle]).
Variables with static storage duration
are initialized as a consequence of program initiation. Variables with
thread storage duration are initialized as a consequence of thread execution.
Within each of these phases of initiation, initialization occurs as follows.
A constant initializer for a variable or temporary object o
is an initializer whose full-expression is a
constant expression, except that if o is an object,
such an initializer may also invoke constexpr constructors
for o and its subobjects even if those objects are of non-literal class
types. [ Note: Such a class may have a non-trivial destructor. — end note ]
Constant initialization is performed
if a variable or temporary object with static or thread storage duration
is initialized by a constant initializer for the entity.
If constant initialization is not performed, a variable with static
storage duration or thread storage
duration is zero-initialized.
Together, zero-initialization and constant initialization are called
static initialization;
all other initialization is dynamic initialization.
All static initialization strongly happens before ([intro.races])
any dynamic initialization.
[ Note: The dynamic initialization of non-local variables is described
in [basic.start.dynamic]; that of local static variables is described
in [stmt.dcl]. — end note ]
An implementation is permitted to perform the initialization of a
variable with static or thread storage duration as a static
initialization even if such initialization is not required to be done
statically, provided that
the dynamic version of the initialization does not change the
value of any other object of static or thread storage duration
prior to its initialization, and
the static version of the initialization produces the same value
in the initialized variable as would be produced by the dynamic
initialization if all variables not required to be initialized statically
were initialized dynamically.
[ Note:
As a consequence, if the initialization of an object obj1 refers to an
object obj2 of namespace scope potentially requiring dynamic initialization and defined
later in the same translation unit, it is unspecified whether the value of obj2 used
will be the value of the fully initialized obj2 (because obj2 was statically
initialized) or will be the value of obj2 merely zero-initialized. For example,
inline double fd() { return 1.0; }
extern double d1;
double d2 = d1; double d1 = fd();
— end note ]
Dynamic initialization of a non-local variable with static storage duration is
unordered if the variable is an implicitly or explicitly instantiated
specialization, is partially-ordered if the variable
is an inline variable that is not an implicitly or explicitly instantiated
specialization, and otherwise is ordered.
[ Note: An explicitly specialized non-inline static data member or
variable template specialization has ordered initialization. — end note ]
Dynamic initialization of non-local variables V and W
with static storage duration are ordered as follows:
If V and W have
ordered initialization and V is defined before W within
a single translation unit, the initialization of V is sequenced
before the initialization of W.
If V has partially-ordered initialization, W does not have
unordered initialization, and V is defined before W in
every translation unit in which W is defined, then
if the program starts a thread ([intro.multithread])
other than the main thread ([basic.start.main]),
the initialization of V
strongly happens before
the initialization of W;
otherwise,
the initialization of V
is sequenced before
the initialization of W.
Otherwise, if the program starts a thread
other than the main thread
before either V or W is initialized,
it is unspecified in which threads
the initializations of V and W occur;
the initializations are unsequenced if they occur in the same thread.
Otherwise, the initializations of V and W are indeterminately sequenced.
[ Note:
This definition permits initialization of a sequence of
ordered variables concurrently with another sequence.
— end note ]
It is implementation-defined
whether the dynamic initialization of a
non-local non-inline variable with static storage duration
is sequenced before the first statement of main or is deferred.
If it is deferred, it strongly happens before
any non-initialization odr-use
of any non-inline function or non-inline variable
defined in the same translation unit as the variable to be initialized.
It is implementation-defined
in which threads and at which points in the program such deferred dynamic initialization occurs.
[ Note:
Such points should be chosen in a way that allows the programmer to avoid deadlocks.
— end note ]
[ Example:
#include "a.h"
#include "b.h"
B b;
A::A(){
b.Use();
}
#include "a.h"
A a;
#include "a.h"
#include "b.h"
extern A a;
extern B b;
int main() {
a.Use();
b.Use();
}
It is implementation-defined
whether either a or b is
initialized before main is entered or whether the
initializations are delayed until a is first odr-used in
main. In particular, if a is initialized before
main is entered, it is not guaranteed that b will be
initialized before it is odr-used by the initialization of a, that
is, before A::A is called. If, however, a is initialized
at some point after the first statement of main, b will
be initialized prior to its use in A::A. — end example ]
It is implementation-defined
whether the dynamic initialization of a
non-local inline variable with static storage duration
is sequenced before the first statement of main or is deferred.
If it is deferred, it strongly happens before
any non-initialization odr-use
of that variable.
It is implementation-defined
in which threads and at which points in the program such deferred dynamic initialization occurs.
It is implementation-defined
whether the dynamic initialization of a
non-local non-inline variable with thread storage duration
is sequenced before the first statement of the initial function of a thread or is deferred.
If it is deferred,
the initialization associated with the entity for thread t
is sequenced before the first non-initialization odr-use by t
of any non-inline variable with thread storage duration
defined in the same translation unit as the variable to be initialized.
It is implementation-defined
in which threads and at which points in the program such deferred dynamic initialization occurs.
If the initialization of a non-local variable with static or thread storage duration
exits via
an exception, std::terminate is called.
Destructors for initialized objects
(that is, objects whose lifetime has begun)
with static storage duration,
and functions registered with std::atexit,
are called as part of a call to
std::exit.
The call to std::exit is sequenced before
the invocations of the destructors and the registered functions.
[ Note:
Returning from main invokes std::exit ([basic.start.main]).
— end note ]
Destructors for initialized objects with thread storage duration within a given thread
are called as a result of returning from the initial function of that thread and as a
result of that thread calling std::exit.
The completions of the destructors for all initialized objects with thread storage
duration within that thread strongly happen before the initiation of the destructors of
any object with static storage duration.
If the completion of the constructor or dynamic initialization of an object with static
storage duration strongly happens before that of another, the completion of the destructor
of the second is sequenced before the initiation of the destructor of the first.
If the completion of the constructor or dynamic initialization of an object with thread
storage duration is sequenced before that of another, the completion of the destructor
of the second is sequenced before the initiation of the destructor of the first.
If an object is
initialized statically, the object is destroyed in the same order as if
the object was dynamically initialized. For an object of array or class
type, all subobjects of that object are destroyed before any block-scope
object with static storage duration initialized during the construction
of the subobjects is destroyed.
If the destruction of an object with static or thread storage duration
exits via an exception,
std::terminate is called.
If a function contains a block-scope object of static or thread storage duration that has been
destroyed and the function is called during the destruction of an object with static or
thread storage duration, the program has undefined behavior if the flow of control
passes through the definition of the previously destroyed block-scope object. Likewise, the
behavior is undefined if the block-scope object is used indirectly (i.e., through a
pointer) after its destruction.
If the completion of the initialization of an object with static storage
duration strongly happens before a call to std::atexit (see
<cstdlib>, [support.start.term]), the call to the function passed to
std::atexit is sequenced before the call to the destructor for the object. If a
call to std::atexit strongly happens before the completion of the initialization of
an object with static storage duration, the call to the destructor for the
object is sequenced before the call to the function passed to std::atexit. If a
call to std::atexit strongly happens before another call to std::atexit, the
call to the function passed to the second std::atexit call is sequenced before
the call to the function passed to the first std::atexit call.
If there is a use of a standard library object or function not permitted within signal
handlers ([support.runtime]) that does not
happen before
completion of destruction of objects with static storage duration and execution of
std::atexit registered functions ([support.start.term]), the program has
undefined behavior. [ Note: If there is a use of an object with static storage
duration that does not happen before the object's destruction, the program has undefined
behavior. Terminating every thread before a call to std::exit or the exit from
main is sufficient, but not necessary, to satisfy these requirements. These
requirements permit thread managers as static-storage-duration objects. — end note ]
Calling the function std::abort() declared in
<cstdlib> terminates the program without executing any destructors
and without calling
the functions passed to std::atexit() or std::at_quick_exit().