A program shall contain a global function called main, which is the designated
start of the program. 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. It shall have a return type of type
int, but otherwise its type is implementation-defined.
All implementations shall allow both of the following definitions of
main:
int main() { /* ... */ }
and
int main(int argc, char* argv[]) { /* ... */ }
In the latter form 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 ([basic.link]) 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 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) ([support.start.term])) 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 reaches the end of main without encountering a
return statement, the effect is that of executing
return 0;
There are two broad classes of named non-local variables: those with static storage
duration ([basic.stc.static]) and those with thread storage
duration ([basic.stc.thread]). Non-local variables with static storage duration
are initialized as a consequence of program initiation. Non-local variables with
thread storage duration are initialized as a consequence of thread execution.
Within each of these phases of initiation, initialization occurs as follows.
Variables with static storage duration ([basic.stc.static]) or thread storage
duration ([basic.stc.thread]) shall be zero-initialized ([dcl.init]) before
any other initialization takes place.
Constant initialization is performed:
if each full-expression (including implicit conversions) that appears in
the initializer of a reference with static or thread storage duration is a
constant expression ([expr.const]) and the reference is bound to an lvalue
designating an object with static storage duration or to a temporary (see [class.temporary]);
if an object with static or thread storage duration is initialized
by a constructor call, if the constructor is a constexpr constructor, if all constructor
arguments are constant expressions (including conversions), and if, after function
invocation substitution ([dcl.constexpr]), every constructor call and full-expression in
the mem-initializers
and in the brace-or-equal-initializers for non-static data members
is a constant expression;
if an object with static or thread storage duration is not initialized by a constructor call
and if every full-expression that appears in its initializer is a constant expression.
Together, zero-initialization and constant initialization are called static
initialization; all other initialization is dynamic initialization. Static
initialization shall be performed before any dynamic initialization takes place. Dynamic
initialization of a non-local variable with static storage duration is either ordered or
unordered. Definitions of explicitly specialized class template static data members have
ordered initialization. Other class template static data members (i.e., implicitly or
explicitly instantiated specializations) have unordered initialization. Other non-local
variables with static storage duration have ordered initialization. Variables with ordered
initialization defined within a single translation unit shall be initialized in the order of
their definitions in the translation unit. If a program starts a thread ([thread.threads]),
the subsequent initialization of a variable is unsequenced with respect to the initialization
of a variable defined in a different translation unit. Otherwise, the initialization of a
variable is indeterminately sequenced with respect to the initialization of a variable defined
in a different translation unit. If a program starts a thread, the subsequent unordered
initialization of a variable is unsequenced with respect to every other dynamic initialization.
Otherwise, the unordered initialization of a variable is indeterminately sequenced with respect
to every other dynamic initialization. [ Note: This definition permits initialization of a
sequence of ordered variables concurrently with another sequence. — end note ] [ Note: The
initialization of local static variables is described in [stmt.dcl]. — end note ]
An implementation is permitted to perform the initialization of a
non-local variable with static 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 namespace scope 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 ]
It is implementation-defined whether the
dynamic initialization of a non-local variable with static storage duration is
done before the first statement of main. If the initialization is deferred to
some point in time after the first statement of main, it shall occur before the
first odr-use ([basic.def.odr]) of any function or variable
defined in the same translation unit as the variable
to be initialized.
[ 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 variable with static or
thread storage duration
is done before the first statement of the initial function of the thread. If the
initialization is deferred to some point in time after the first statement of the
initial function of the thread, it shall occur before the first
odr-use ([basic.def.odr]) of any variable with
thread storage duration defined in the same translation unit as the variable to be
initialized.
If the initialization of a non-local variable with static or thread storage duration
exits via
an exception, std::terminate is called ([except.terminate]).
Destructors ([class.dtor]) for initialized objects
(that is, objects whose lifetime ([basic.life]) has begun)
with static storage duration
are called as a result of returning from main and as a result of calling
std::exit ([support.start.term]).
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 are sequenced 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 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 the completion of the constructor or dynamic initialization of an object with static
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.
[ Note: This definition permits concurrent destruction. — end note ] 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 ([except.terminate]).
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 is sequenced 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 is sequenced 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 is sequenced 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 ([intro.multithread])
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().