首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

C++ 0初始化,静态初始化和动态初始化有关问题

2013-08-04 
C++ 0初始化,静态初始化和动态初始化问题看到有资料(google的网页)说,C++的初始化过程分为三个步骤:1. 0初

C++ 0初始化,静态初始化和动态初始化问题
看到有资料(google的网页)说,C++的初始化过程分为三个步骤:
1. 0初始化,对象/变量赋值为0;zero initialization
2. 静态初始化;static initialization
3. 动态初始化。dynamic initialization

我着实没搞懂到底怎么个分步骤法。有的说步骤1和2在编译时就完成了,而3则要运行时才确定。很多疑惑随之而来。没有一个资料明确说什么是静态初始化和动态初始化。倒是在C++标准里面有一句话是这样的:

引用
Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place. Zero-initialization and initialization with a constant expression are collectively called static initialization; all other initialization is dynamic initialization

但是标准里面却没有说初始化的确切时间和顺序以及含义。我在这里先给出我的猜想:
1. 0初始化应该是编译时可以确定的,在虚拟地址空间的对应地址设置为0.
2. 静态初始化是指给静态变量初始化,就是那些static关键字开头的变量。也是编译时确定了,只需要直接在虚拟空间相应地址设置为相应的值即可。这里有一个疑问,我用readelf/objdump看可执行文件时,好像磁盘上的可执行文件里面没有关于静态初始化的值的信息。如,static int a = 5; 如果真是在编译时确定了,那么这个初始值5到底存放在什么地方?不可能真的放在a的虚拟空间地址那里,因为虚拟空间是不存在的,怎么放啊?是不是可执行文件在磁盘上也是按照虚拟空间那样分布,在磁盘的对应位置给a地址那里放一个5?
3. 动态初始化是指给new/malloc分配的对象/变量初始化,需要在运行才能确定,我的估计是在main之前就已经运行这些初始化了。

我说了好多,只是些零星的知识,希望各位不灵赐教,各条一一反驳讲解,也可以帮助大家互相学习!
[解决办法]
2. 放在可执行文件中的 .data 段中的. 段的属性里面会指明它加载到内存后对应的内存地址. 操作系统会按这个属性进行加载. 所以, 文件中的数据是可以直接和内存中的数据对应的.
[解决办法]
引用:
Quote: 引用:

楼主标准还得再看仔细点儿。

3.6.2/2
Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization.

所以主楼写的三个步骤是不对滴,因为 zero-initialization 就是 static initialization 的一部分,不存在先 zero-initialization 再 static initialization 的问题,执行了前者就意味着也执行了后者。

另外 dynamic initialization 和 new/delete 没有关系,后面那俩关联的概念叫 dynamic memory allocation,虽然都用了 dynamic 这个词,但是木有必然联系。

dynamic initialization 是和 static initialization 对立的概念,所有 initialization 分为两类,一类叫 static initialization,标准明确说此类包含零初始化和 constant initialization;所有不能放在这类的初始化动作都叫 dynamic initialization. 举个简单的例子



struct test_t
{
 test_t () : data(1) { /* non-trivial initialization */ }
 size_t data;
};
static test_t const a_non_local_static_object;

对于这个例子,标准要求首先执行 static initialization,鉴于没有 constant initialization 可以执行,所以执行 zero initialization,因此 a_non_local_static_object.data 首先会被赋值为 0。

当后序程序需要用到 a_non_local_static_object 的时候,标准要求在第一次使用前完成 dynamic initialization,即调用 test_t 的默认构造函数,初始化 a_non_local_static_object.data 为 1.

当然,a_non_local_static_object.data = 0 这不在这个例子里显然是浪费时间,因此标准 3.6.2/3 特别允许可以把 a_non_local_static_object.data = 1 放在 static initialization 里面完成,即原来 a_non_local_static_object.data = 0 的操作换成直接赋值为 1.

还是你读标准读的仔细。我发现标准有个问题,每一句话里面修饰的成分超级多,有时读着挺吃力的,修饰的条件一多了就很难每条都记住,不像是一个通用的rule。

英文确实够绕,但也不能怪标准,毕竟要面向全世界所有人,可能通俗易懂的版本足够对付 99.9% 的情况,但偏偏有那么几个特殊案例需要更全面的陈述,最后取个合集,就是只能这样子了。

引用:
再贴一个标准里的例子,比较特殊:
引用
[ 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 ]

这个行为是undefined

介个不是 undefined,是 unspecified。前者没有任何保证正确,后者在特定实现下还是可以 well-defined.
比如上面的例子,某编译器文档说明保证不做任何优化,严格按照标准给定的初始化顺序进行,那么 d2 一定是 0,是个 well-defined 行为。但这种行为只是该编译器的特定情况,换个编译器可能就是另一种情况了,也可能会变成 undefined.

热点排行