Initialization
初始化
初始化
变量在构造时提供它的初始值。
初始值可以在报关员或者是新表达式在函数调用过程中也会发生:函数参数和函数返回值也会被初始化。
对于每个声明器,初始化程序可以是下列之一:
( expression-list ) | (1) | |
---|---|---|
= expression | (2) | |
{ initializer-list } | (3) | |
1%29用逗号分隔的任意表达式列表和括号中的大括号
2%29等号后面跟着表达式
3%29大括号-init-list:可能是空的、逗号分隔的表达式列表和其他大括号-init-列表。
根据上下文的不同,初始化程序可以调用以下内容之一:
- 值初始化,G.
std::string
s{};
- 直接初始化,G.
std::string
s("hello"
- 复制初始化,G.
std::string
s =
"hello";
- 列表初始化,G.
std::string
s{'a', 'b', 'c'};
- 聚合初始化,G.
char a[3] = {'a', 'b'};
- 参考初始化,G.
char& c = a[0];
如果没有提供初始化程序,则默认初始化申请。
非局部变量
所有具有静态的非局部变量存储时间的执行之前,作为程序启动的一部分进行初始化。主要功能除非延迟,否则开始%28,请参阅%29下面。在线程函数开始执行之前,所有具有线程本地存储持续时间的变量都会作为线程启动的一部分进行初始化,并进行排序。对于这两类变量,初始化分为两个不同的阶段:
静态初始化
1%29如果允许的话,常数初始化发生的第一次%28见常数初始化关于这些情况的列表%29。在实践中,常量初始化通常在编译时执行,预计算的对象表示作为程序映像的一部分存储。如果编译器不执行此操作,则仍必须保证在任何动态初始化之前进行此初始化。
2%29对于所有其他非本地静态和线程局部变量,零初始化发生了。实际上,将被零初始化的变量放置在.bss
程序映像段,它在磁盘上没有占用空间,在加载程序时由操作系统将其归零。
动态初始化
在完成所有静态初始化之后,在以下情况下会动态初始化非局部变量:
1%29无序动态初始化
,它仅适用于%28静态/线程-本地%29类模板。静态数据成员和可变模板%28自C++14%29,即%27T显式专业化这些静态变量的初始化相对于所有其他动态初始化都是不确定的顺序,除非程序在初始化变量之前启动线程,在这种情况下,自C++17%29以来,其初始化为未排序的%28。此类线程局部变量的初始化与所有其他动态初始化无关.
2) Partially-ordered dynamic initialization, which applies to all inline variables that are not an implicitly or explicitly instantiated specialization. If a partially-ordered V is defined before ordered or partially-ordered W in every translation unit, the initialization of V is sequenced before the initialization of W (or happens-before, if the program starts a thread) | (since C++17) |
---|
3%29有序动态初始化
,它适用于所有其他非局部变量:在单个转换单元中,这些变量的初始化始终是定序按照确切的顺序,它们的定义出现在源代码中。在不同的翻译单元中静态变量的初始化是不确定的。不同翻译单元中线程局部变量的初始化是不被排序的.
如果具有静态或线程存储持续时间的非局部变量的初始化通过异常退出,std::terminate
叫做。
早期动态初始化
如果以下条件都是正确的,编译器可以在编译时(%29)作为静态初始化%28的一部分来动态初始化初始化变量:
1%29初始化的动态版本在初始化之前不会更改名称空间作用域的任何其他对象的值。
2%29如果所有不需要静态初始化的变量都是动态初始化的,则初始化的静态版本在初始化变量中产生的值与动态初始化产生的值相同。
因为上面的规则,如果初始化某个对象o1
引用命名空间范围对象。o2
,它可能需要动态初始化,但稍后在同一翻译单元中定义,则未指定o2
使用的值是完全初始化的值。o2
%28,因为编译器提升了o2
编译时间%29或将为o2
只是零初始化。
二次
inline double fd() { return 1.0; }
extern double d1;
double d2 = d1; // unspecified:
// dynamically initialized to 0.0 if d1 is dynamically initialized, or
// dynamically initialized to 1.0 if d1 is statically initialized, or
// statically initialized to 0.0 (because that would be its value
// if both variables were dynamically initialized)
double d1 = fd( // may be initialized statically or dynamically to 1.0
二次
延迟动态初始化
它是实现--定义是否发生动态初始化--在主函数%28的第一条语句之前(静态%29),或者线程%28的初始函数(对于线程-局部变量%29)之前,或者推迟到之后发生。
如果将非内联变量的初始化推迟到main/线程函数的第一条语句之后,则在第一条语句之前进行。ODR-使用在要初始化的变量的同一个转换单元中定义具有静态/线程存储持续时间的任何变量。如果没有从给定的翻译单元中使用ODR的变量或函数,那么在该翻译单元中定义的非局部变量可能永远不会初始化%28,这将建模按需动态库%29的行为。但是,只要使用来自TU的任何内容,所有初始化或销毁都有副作用的非局部变量都将初始化,即使它们不在程序中使用。
If the initialization of an inline variable is deferred, it happens before the first odr-use of that specific variable. | (since C++17) |
---|
二次
// - 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(
// if a is initialized before main is entered, b may still be uninitialized
// at the point where A::A() uses it (because dynamic init is indeterminately sequenced
// across translation units)
// If a is initialized at some point after the first statement of main (which odr-uses
// a function defined in File 1, forcing its dynamic initialization to run),
// then b will be initialized prior to its use in A::A
二次
静态局部变量
有关局部变量%28的初始化(即块作用域%29静态和线程局部变量),请参见静态局部变量...
班级成员
非静态数据成员可以用成员初始化列表或者用一个默认成员初始化器...
注记
非局部变量的破坏顺序在std::exit
...
缺陷报告
以下行为更改缺陷报告追溯应用于先前发布的C++标准。
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 2026 | C++14 | zero-init was specified to always occur first, even before constant-init | no zero-init if constant init applies |
另见
C初始化文档
*。
© cppreference.com
在CreativeCommonsAttribution下授权-ShareAlike未移植许可v3.0。