6 Basic concepts [basic]

6.8 Program execution [basic.exec]

6.8.3 Start and termination [basic.start]

6.8.3.1 main function [basic.start.main]

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
  • a function of () returning int and
  • a function of (int, pointer to pointer to char) returning int
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 (ntmbss) ([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 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) ([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 flows off the end of the compound-statement of main, the effect is equivalent to a return with operand 0 (see also [except.handle]).

6.8.3.2 Static initialization [basic.start.static]

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 ([basic.stc.static]) or thread storage duration ([basic.stc.thread]) is zero-initialized ([dcl.init]).
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;     // unspecified:
                    // may be statically initialized to 0.0 or
                    // dynamically initialized to 0.0 if d1 is
                    // dynamically initialized, or 1.0 otherwise
double d1 = fd();   // may be initialized statically or dynamically to 1.0
end note
]

6.8.3.3 Dynamic initialization of non-local variables [basic.start.dynamic]

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
]
A non-initialization odr-use is an odr-use ([basic.def.odr]) not caused directly or indirectly by the initialization of a non-local static or thread storage duration variable.
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.55
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
:
// - File 1 -
#include "a.h"
#include "b.h"
B b;
A::A(){
  b.Use();
}

// - File 2 -
#include "a.h"
A a;

// - File 3 -
#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 ([except.terminate]).
A non-local variable with static storage duration having initialization with side effects is initialized in this case, even if it is not itself odr-used ([basic.def.odr], [basic.stc.static]).

6.8.3.4 Termination [basic.start.term]

Destructors ([class.dtor]) for initialized objects (that is, objects whose lifetime ([basic.life]) has begun) with static storage duration, and functions registered with std​::​atexit, are called as part of a call to std​::​exit ([support.start.term]).
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 ([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 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 ([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().