C++中变量的初始化

来自 http://zh.cppreference.com/w/cpp/language/initialization. 以下为个人备忘, 并不完全. 未免误导, 请移至原文.

概述

变量的初始化即在构建变量、分配空间时赋予一个初始的值. 这可能发生在声明定义变量时、使用new expression动态分配变量存储空间时. 当然在函数调用中有传参及返回值时也会发生. 一般来说, 声明器(initializer) 有以下几种表现形式:

  • (expression-list)
  • = expression
  • {initializer-list}

分类

  • 默认初始化(default initialization). 比如int x; int* y = new int(); int* z = new int;
  • 值初始化(value initialization). 比如std::string str{};
  • 直接初始化(direct initialization). 比如std::string str("Hello");
  • 拷贝初始化(copy initialization).比如std::string str = "Hello";
  • 列表初始化(list initialization). 比如std::string str{'a', 'b'};
  • 集合初始化(aggregate initialization). 比如char chs[2] = {'a', 'b'};
  • 引用初始化(reference initialization). 比如char& i = chs[0];

初始化顺序

  • 对于拥有静态储存期的非局部变量将做为程序启动初始化的一部分.
    1. 若受允许,则首先发生常量初始化(这些情形见常量初始化)。 实践上,常量初始化通常在编译期进行,而预计算的对象表示作为程序映像的一部分存储。若编译器没有这么做,则亦保证此初始化发生先于任何动态初始化。
    2. 对于所有其他非局部静态及线程局域变量(相对的全局变量),发生零初始化。 实现中,要被零初始化的变量置于程序映像的 .bss 段,它不占据磁盘空间,并在加载程序时为操作系统以零填充。
  • 动态初始化在所有静态初始化完成后,非局部变量的动态初始化在下列情形出现:
    • 无序动态初始化 用于那种没有显式特化的模板类中的静态成员.相对于其他动态初始化, 表现为无序.(注: 简化了描述, 少了许多定语. 标准定义才可供参考.)
    • 部分有序动态初始化 用于非显式或隐式特化的inline变量. 在同一源文件中的顺序为其定义出现的先后顺序(非同一源文件顺序不定).
    • 有序动态初始化 用于所有其他非局部变量(比如new 出来的对象). 初始化顺序依其在同一源文件中的定义先后. 不同源文件的静态变量初始化顺序不定. 不同线程内的线程域变量(thread-local variables)初始化无序.
    • 早期动态初始化 编译期进行(是允许编译器进行编译期初始化, 就如静态初始化一样). 前提是同时满足下列两个条件:
      • 在同一名称空间内, 变量没有发生写内存操作时(除了初始化).
      • 假设该变量的静态版本初始化时与该变量产生相同的值时(?).
/*

**Early dynamic initialization**

The compilers are allowed to initialize dynamically-initialized variables as part of static initialization (essentially, at compile time), if the following conditions are both true:

1) the dynamic version of the initialization does not change the value of any other object of namespace scope prior to its initialization

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.
Because of the rule above, if initialization of some object o1 refers to an namespace-scope object o2, which potentially requires dynamic initialization, but is defined later in the same translation unit, it is unspecified whether the value of o2 used will be the value of the fully initialized o2 (because the compiler promoted initialization of o2 to compile time) or will be the value of o2 merely zero-initialized.

*/

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
  • 延迟动态初始化

/*

**Deferred dynamic initialization**

It is implementation-defined whether dynamic initialization happens-before the first statement of the main function (for statics) or the initial function of the thread (for thread-locals), or deferred to happen after.

If the initialization of a non-inline variable is deferred to happen after the first statement of main/thread function, it happens before the first odr-use of any variable with static/thread storage duration defined in the same translation unit as the variable to be initialized. If no variable or function is odr-used from a given translation unit, the non-local variables defined in that translation unit may never be initialized (this models the behavior of an on-demand dynamic library). However, as long as anything from a TU is odr-used, all non-local variables whose initialization or destruction has side effects will be initialized even if they are not used in the program.

If the initialization of an inline variable is deferred, it happens before the first odr-use of that specific variable.

*/

// - 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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值