516 lines
22 KiB
Markdown
516 lines
22 KiB
Markdown
[basic.start]
|
||
|
||
# 6 Basics [[basic]](./#basic)
|
||
|
||
## 6.10 Program execution [[basic.exec]](basic.exec#basic.start)
|
||
|
||
### 6.10.3 Start and termination [basic.start]
|
||
|
||
#### [6.10.3.1](#main) main function [[basic.start.main]](basic.start.main)
|
||
|
||
[1](#main-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7129)
|
||
|
||
A program shall contain exactly one function called main that belongs to the global scope[.](#main-1.sentence-1)
|
||
|
||
Executing a program starts a main thread of execution ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"), [[thread.threads]](thread.threads "32.4 Threads"))
|
||
in which the main function is invoked[.](#main-1.sentence-2)
|
||
|
||
It is implementation-defined
|
||
whether a program in a freestanding environment is required to define a main function[.](#main-1.sentence-3)
|
||
|
||
[*Note [1](#main-note-1)*:
|
||
|
||
In a freestanding environment, startup and termination isimplementation-defined; startup contains the
|
||
execution of constructors for non-local objects with static storage duration;
|
||
termination contains the execution of destructors for objects with static storage
|
||
duration[.](#main-1.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[2](#main-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7147)
|
||
|
||
An implementation shall not predefine the main function[.](#main-2.sentence-1)
|
||
|
||
Its type shall have C++ language linkage
|
||
and it shall have a declared return type of typeint, but otherwise its type is implementation-defined[.](#main-2.sentence-2)
|
||
|
||
An implementation shall allow both
|
||
|
||
- [(2.1)](#main-2.1)
|
||
|
||
a function of () returning int and
|
||
|
||
- [(2.2)](#main-2.2)
|
||
|
||
a function of (int, pointer to pointer to char) returning int
|
||
|
||
as the type of main ([[dcl.fct]](dcl.fct "9.3.4.6 Functions"))[.](#main-2.sentence-3)
|
||
|
||
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[.](#main-2.sentence-4)
|
||
|
||
Ifargc is nonzero these arguments shall be supplied inargv[0] through argv[argc - 1] as pointers to the initial
|
||
characters of null-terminated multibyte strings (ntmbss) ([[multibyte.strings]](multibyte.strings "16.3.3.3.4.3 Multibyte strings"))
|
||
and argv[0] shall be the pointer to
|
||
the initial character of an ntmbs that represents the name used to
|
||
invoke the program or ""[.](#main-2.sentence-5)
|
||
|
||
The value of argc shall be
|
||
non-negative[.](#main-2.sentence-6)
|
||
|
||
The value of argv[argc] shall be 0[.](#main-2.sentence-7)
|
||
|
||
*Recommended practice*: Any further (optional) parameters should be added after argv[.](#main-2.sentence-8)
|
||
|
||
[3](#main-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7179)
|
||
|
||
The function main shall not be named by an expression[.](#main-3.sentence-1)
|
||
|
||
The linkage ([[basic.link]](basic.link "6.7 Program and linkage")) of main isimplementation-defined[.](#main-3.sentence-2)
|
||
|
||
A program that defines main as
|
||
deleted or that declares main to beinline, static, constexpr, or consteval is ill-formed[.](#main-3.sentence-3)
|
||
|
||
The function main shall not be a coroutine ([[dcl.fct.def.coroutine]](dcl.fct.def.coroutine "9.6.4 Coroutine definitions"))[.](#main-3.sentence-4)
|
||
|
||
The main function shall not be declared with a[*linkage-specification*](dcl.link#nt:linkage-specification "9.12 Linkage specifications [dcl.link]") ([[dcl.link]](dcl.link "9.12 Linkage specifications")) other than "C++"[.](#main-3.sentence-5)
|
||
|
||
A program that declares
|
||
|
||
- [(3.1)](#main-3.1)
|
||
|
||
a variable main that belongs to the global scope, or
|
||
|
||
- [(3.2)](#main-3.2)
|
||
|
||
a function main that belongs to the global scope and
|
||
is attached to a named module, or
|
||
|
||
- [(3.3)](#main-3.3)
|
||
|
||
a function template main that belongs to the global scope, or
|
||
|
||
- [(3.4)](#main-3.4)
|
||
|
||
an entity named main with C language linkage (in any namespace)
|
||
|
||
is ill-formed[.](#main-3.sentence-6)
|
||
|
||
The name main is
|
||
not otherwise reserved[.](#main-3.sentence-7)
|
||
|
||
[*Example [1](#main-example-1)*:
|
||
|
||
Member functions, classes, and
|
||
enumerations can be called main, as can entities in other
|
||
namespaces[.](#main-3.sentence-8)
|
||
|
||
â *end example*]
|
||
|
||
[4](#main-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7211)
|
||
|
||
Terminating the program
|
||
without leaving the current block (e.g., by calling the functionstd::exit(int) ([[support.start.term]](support.start.term "17.5 Startup and termination"))) does not destroy any
|
||
objects with automatic storage duration ([[class.dtor]](class.dtor "11.4.7 Destructors"))[.](#main-4.sentence-1)
|
||
|
||
Ifstd::exit is invoked during the destruction of
|
||
an object with static or thread storage duration, the program has undefined
|
||
behavior[.](#main-4.sentence-2)
|
||
|
||
[5](#main-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7223)
|
||
|
||
A return statement ([[stmt.return]](stmt.return "8.8.4 The return statement")) in main has the effect of leaving the main function (destroying any objects with automatic storage duration
|
||
and evaluating any postcondition assertions of main)
|
||
and calling std::exit with the return value as the argument[.](#main-5.sentence-1)
|
||
|
||
If control flows off the end of
|
||
the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") of main,
|
||
the effect is equivalent to a return with operand 0 (see also [[except.handle]](except.handle "14.4 Handling an exception"))[.](#main-5.sentence-2)
|
||
|
||
#### [6.10.3.2](#static) Static initialization [[basic.start.static]](basic.start.static)
|
||
|
||
[1](#static-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7238)
|
||
|
||
Variables with static storage duration
|
||
are initialized as a consequence of program initiation[.](#static-1.sentence-1)
|
||
|
||
Variables with
|
||
thread storage duration are initialized as a consequence of thread execution[.](#static-1.sentence-2)
|
||
|
||
Within each of these phases of initiation, initialization occurs as follows[.](#static-1.sentence-3)
|
||
|
||
[2](#static-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7246)
|
||
|
||
[*Constant initialization*](#def:constant_initialization "6.10.3.2 Static initialization [basic.start.static]") is performed
|
||
if a variable with static or thread storage duration
|
||
is constant-initialized ([[expr.const]](expr.const "7.7 Constant expressions"))[.](#static-2.sentence-1)
|
||
|
||
If constant initialization is not performed, a variable with static
|
||
storage duration ([[basic.stc.static]](basic.stc.static "6.8.6.2 Static storage duration")) or thread storage
|
||
duration ([[basic.stc.thread]](basic.stc.thread "6.8.6.3 Thread storage duration")) is zero-initialized ([[dcl.init]](dcl.init "9.5 Initializers"))[.](#static-2.sentence-2)
|
||
|
||
Together, zero-initialization and constant initialization are called[*static initialization*](#def:initialization,static "6.10.3.2 Static initialization [basic.start.static]");
|
||
all other initialization is [*dynamic initialization*](#def:initialization,dynamic "6.10.3.2 Static initialization [basic.start.static]")[.](#static-2.sentence-3)
|
||
|
||
All static initialization strongly happens before ([[intro.races]](intro.races "6.10.2.2 Data races"))
|
||
any dynamic initialization[.](#static-2.sentence-4)
|
||
|
||
[*Note [1](#static-note-1)*:
|
||
|
||
The dynamic initialization of non-block variables is described
|
||
in [[basic.start.dynamic]](#dynamic "6.10.3.3 Dynamic initialization of non-block variables"); that of static block variables is described
|
||
in [[stmt.dcl]](stmt.dcl "8.10 Declaration statement")[.](#static-2.sentence-5)
|
||
|
||
â *end note*]
|
||
|
||
[3](#static-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7266)
|
||
|
||
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
|
||
|
||
- [(3.1)](#static-3.1)
|
||
|
||
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
|
||
|
||
- [(3.2)](#static-3.2)
|
||
|
||
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[.](#static-3.sentence-1)
|
||
|
||
[*Note [2](#static-note-2)*:
|
||
|
||
As a consequence, if the initialization of an object obj1 refers to an
|
||
object obj2 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[.](#static-3.sentence-2)
|
||
|
||
For example,inline double fd() { return 1.0; }extern double d1;double d2 = d1; // unspecified:// either statically initialized to 0.0 or// dynamically initialized to 0.0 if d1 is// dynamically initialized, or 1.0 otherwisedouble d1 = fd(); // either initialized statically or dynamically to 1.0
|
||
|
||
â *end note*]
|
||
|
||
#### [6.10.3.3](#dynamic) Dynamic initialization of non-block variables [[basic.start.dynamic]](basic.start.dynamic)
|
||
|
||
[1](#dynamic-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7302)
|
||
|
||
Dynamic initialization of a non-block 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[.](#dynamic-1.sentence-1)
|
||
|
||
[*Note [1](#dynamic-note-1)*:
|
||
|
||
A non-inline explicit specialization of a templated variable
|
||
has ordered initialization[.](#dynamic-1.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[2](#dynamic-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7316)
|
||
|
||
A declaration D is[*appearance-ordered*](#def:appearance-ordered "6.10.3.3 Dynamic initialization of non-block variables [basic.start.dynamic]") before a declaration E if
|
||
|
||
- [(2.1)](#dynamic-2.1)
|
||
|
||
D appears in the same translation unit as E, or
|
||
|
||
- [(2.2)](#dynamic-2.2)
|
||
|
||
the translation unit containing E has an interface dependency on the translation unit containing D,
|
||
|
||
in either case prior to E[.](#dynamic-2.sentence-1)
|
||
|
||
[3](#dynamic-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7326)
|
||
|
||
Dynamic initialization of non-block variables V and W with static storage duration are ordered as follows:
|
||
|
||
- [(3.1)](#dynamic-3.1)
|
||
|
||
If V and W have ordered initialization and
|
||
the definition of V is appearance-ordered before the definition of W, or
|
||
if V has partially-ordered initialization,W does not have unordered initialization, and
|
||
for every definition E of W there exists a definition D of V such that D is appearance-ordered before E, then
|
||
* [(3.1.1)](#dynamic-3.1.1)
|
||
|
||
if the program does not start a thread ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))
|
||
other than the main thread ([[basic.start.main]](#main "6.10.3.1 main function"))
|
||
or V and W have ordered initialization and
|
||
they are defined in the same translation unit,
|
||
the initialization of V is sequenced before
|
||
the initialization of W;
|
||
|
||
* [(3.1.2)](#dynamic-3.1.2)
|
||
|
||
otherwise,
|
||
the initialization of V strongly happens before
|
||
the initialization of W[.](#dynamic-3.1.sentence-1)
|
||
|
||
- [(3.2)](#dynamic-3.2)
|
||
|
||
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[.](#dynamic-3.2.sentence-1)
|
||
|
||
- [(3.3)](#dynamic-3.3)
|
||
|
||
Otherwise, the initializations of V and W are indeterminately sequenced[.](#dynamic-3.3.sentence-1)
|
||
|
||
[*Note [2](#dynamic-note-2)*:
|
||
|
||
This definition permits initialization of a sequence of
|
||
ordered variables concurrently with another sequence[.](#dynamic-3.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[4](#dynamic-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7371)
|
||
|
||
A [*non-initialization odr-use*](#def:odr-use,non-initialization "6.10.3.3 Dynamic initialization of non-block variables [basic.start.dynamic]") is an odr-use ([[basic.def.odr]](basic.def.odr#term.odr.use "6.3 One-definition rule")) not caused directly or indirectly by
|
||
the initialization of a non-block static or thread storage duration variable[.](#dynamic-4.sentence-1)
|
||
|
||
[5](#dynamic-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7377)
|
||
|
||
It is implementation-defined
|
||
whether the dynamic initialization of a
|
||
non-block non-inline variable with static storage duration
|
||
is sequenced before the first statement of main or is deferred[.](#dynamic-5.sentence-1)
|
||
|
||
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[.](#dynamic-5.sentence-2)[38](#footnote-38 "A non-block variable with static storage duration having initialization with side effects is initialized in this case, even if it is not itself odr-used ([term.odr.use], [basic.stc.static]).")
|
||
|
||
It is implementation-defined
|
||
in which threads and at which points in the program such deferred dynamic initialization occurs[.](#dynamic-5.sentence-3)
|
||
|
||
*Recommended practice*: An implementation should choose such points in a way
|
||
that allows the programmer to avoid deadlocks[.](#dynamic-5.sentence-4)
|
||
|
||
[*Example [1](#dynamic-example-1)*: // - 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 inmain[.](#dynamic-5.sentence-5)
|
||
|
||
In particular, if a is initialized beforemain 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[.](#dynamic-5.sentence-6)
|
||
|
||
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[.](#dynamic-5.sentence-7)
|
||
|
||
â *end example*]
|
||
|
||
[6](#dynamic-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7437)
|
||
|
||
It is implementation-defined
|
||
whether the dynamic initialization of a
|
||
non-block inline variable with static storage duration
|
||
is sequenced before the first statement of main or is deferred[.](#dynamic-6.sentence-1)
|
||
|
||
If it is deferred, it strongly happens before
|
||
any non-initialization odr-use
|
||
of that variable[.](#dynamic-6.sentence-2)
|
||
|
||
It is implementation-defined
|
||
in which threads and at which points in the program such deferred dynamic initialization occurs[.](#dynamic-6.sentence-3)
|
||
|
||
[7](#dynamic-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7448)
|
||
|
||
It is implementation-defined
|
||
whether the dynamic initialization of a
|
||
non-block non-inline variable with thread storage duration
|
||
is sequenced before the first statement of the initial function of a thread or is deferred[.](#dynamic-7.sentence-1)
|
||
|
||
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[.](#dynamic-7.sentence-2)
|
||
|
||
It is implementation-defined
|
||
in which threads and at which points in the program such deferred dynamic initialization occurs[.](#dynamic-7.sentence-3)
|
||
|
||
[8](#dynamic-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7461)
|
||
|
||
If the initialization of
|
||
a non-block variable with static or thread storage duration
|
||
exits via an exception,
|
||
the function std::terminate is called ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#dynamic-8.sentence-1)
|
||
|
||
[38)](#footnote-38)[38)](#footnoteref-38)
|
||
|
||
A non-block 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.def.odr#term.odr.use "6.3 One-definition rule"), [[basic.stc.static]](basic.stc.static "6.8.6.2 Static storage duration"))[.](#footnote-38.sentence-1)
|
||
|
||
#### [6.10.3.4](#term) Termination [[basic.start.term]](basic.start.term)
|
||
|
||
[1](#term-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7470)
|
||
|
||
Constructed objects ([[dcl.init]](dcl.init "9.5 Initializers"))
|
||
with static storage duration are destroyed
|
||
and functions registered with std::atexit are called as part of a call tostd::exit ([[support.start.term]](support.start.term "17.5 Startup and termination"))[.](#term-1.sentence-1)
|
||
|
||
The call to std::exit is sequenced before
|
||
the destructions and the registered functions[.](#term-1.sentence-2)
|
||
|
||
[*Note [1](#term-note-1)*:
|
||
|
||
Returning from main invokes std::exit ([[basic.start.main]](#main "6.10.3.1 main function"))[.](#term-1.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
[2](#term-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7487)
|
||
|
||
Constructed objects with thread storage duration within a given thread
|
||
are destroyed as a result of returning from the initial function of that thread and as a
|
||
result of that thread calling std::exit[.](#term-2.sentence-1)
|
||
|
||
The destruction of all constructed objects with thread storage
|
||
duration within that thread strongly happens before destroying
|
||
any object with static storage duration[.](#term-2.sentence-2)
|
||
|
||
[3](#term-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7495)
|
||
|
||
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[.](#term-3.sentence-1)
|
||
|
||
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[.](#term-3.sentence-2)
|
||
|
||
If an object is
|
||
initialized statically, the object is destroyed in the same order as if
|
||
the object was dynamically initialized[.](#term-3.sentence-3)
|
||
|
||
For an object of array or class
|
||
type, all subobjects of that object are destroyed before any block
|
||
variable with static storage duration initialized during the construction
|
||
of the subobjects is destroyed[.](#term-3.sentence-4)
|
||
|
||
If the destruction of an object with static or thread storage duration
|
||
exits via an exception,
|
||
the function std::terminate is called ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#term-3.sentence-5)
|
||
|
||
[4](#term-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7512)
|
||
|
||
If a function contains a block variable 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 variable[.](#term-4.sentence-1)
|
||
|
||
[*Note [2](#term-note-2)*:
|
||
|
||
Likewise, the behavior is undefined
|
||
if the block variable is used indirectly (e.g., through a pointer)
|
||
after its destruction[.](#term-4.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[5](#term-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7523)
|
||
|
||
If the completion of the initialization of an object with static storage
|
||
duration strongly happens before a call to std::atexit (see[<cstdlib>](cstdlib.syn#header:%3ccstdlib%3e "17.2.2 Header <cstdlib> synopsis [cstdlib.syn]"), [[support.start.term]](support.start.term "17.5 Startup and termination")), the call to the function passed tostd::atexit is sequenced before the call to the destructor for the object[.](#term-5.sentence-1)
|
||
|
||
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[.](#term-5.sentence-2)
|
||
|
||
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[.](#term-5.sentence-3)
|
||
|
||
[6](#term-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7537)
|
||
|
||
If there is a use of a standard library object or function not permitted within signal
|
||
handlers ([[support.runtime]](support.runtime "17.14 Other runtime support")) that does not happen before ([[intro.multithread]](intro.multithread "6.10.2 Multi-threaded executions and data races"))
|
||
completion of destruction of objects with static storage duration and execution ofstd::atexit registered functions ([[support.start.term]](support.start.term "17.5 Startup and termination")), the program has
|
||
undefined behavior[.](#term-6.sentence-1)
|
||
|
||
[*Note [3](#term-note-3)*:
|
||
|
||
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[.](#term-6.sentence-2)
|
||
|
||
Terminating every thread before a call to std::exit or the exit frommain is sufficient, but not necessary, to satisfy these requirements[.](#term-6.sentence-3)
|
||
|
||
These
|
||
requirements permit thread managers as static-storage-duration objects[.](#term-6.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[7](#term-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/basic.tex#L7551)
|
||
|
||
Calling the function std::abort() declared in[<cstdlib>](cstdlib.syn#header:%3ccstdlib%3e "17.2.2 Header <cstdlib> synopsis [cstdlib.syn]") terminates the program without executing any destructors
|
||
and without calling
|
||
the functions passed to std::atexit() or std::at_quick_exit()[.](#term-7.sentence-1)
|