6.2.4 对象的存储期
IMPORTANT
“存储期”决定对象活多久,不是决定名字能看见多久。名字能不能用,看作用域;对象什么时候存在,看存储期。
对象具有一种决定其生存期的存储期。存储期共有四种:静态存储期、线程存储期、自动存储期和分配存储期。分配存储期见 7.24.3。
对象的生存期,是程序执行过程中为它保留存储的那一段时间。对象在其生存期内存在、具有恒定地址,24)并保持其最后一次存储的值。25)如果在对象生存期之外引用它,则行为未定义。如果在对象生存期结束之后,对一个指向该对象(或刚好越过该对象末尾)的指针值进行求值,则行为未定义。当它所指向的对象(或刚好越过该对象末尾)到达生存期末尾时,指针对象的表示会变为不确定表示。
如果某对象的标识符声明时不带存储类说明符
thread_local,并且满足以下任一条件:- 具有外部链接;
- 具有内部链接;
- 带有存储类说明符
static;
那么它具有静态存储期。它的生存期贯穿整个程序执行,并且其存储值只在程序启动之前初始化一次。
如果某对象的标识符使用存储类说明符
thread_local声明,那么它具有线程存储期。它的显式或隐式初始化器在程序执行之前求值;它的生存期贯穿创建它的那个线程的整个执行过程;在线程启动时,它的存储值会被初始化为先前确定的值。每个线程都有一个彼此独立的对象实例;在表达式中使用这个已声明名称时,指向的是正在求值该表达式的线程所关联的那个对象。若试图从与该对象所在线程不同的线程间接访问线程存储期对象,则结果由实现定义。如果某对象的标识符没有链接,并且不带存储类说明符
static,那么它具有自动存储期;某些复合字面量也是如此。若试图从与该对象所在线程不同的线程间接访问自动存储期对象,则结果由实现定义。对这类不具有变长数组类型的对象,其生存期从进入与它关联的块时开始,到该块以任何方式结束执行时终止。(进入某个内层块或调用函数,会挂起当前块的执行,但不会结束它。)如果该块被递归进入,则每次都会创建该对象的一个新实例。对象的初始表示是不确定的。如果为对象指定了初始化,并且没有使用
constexpr,那么每次程序执行到该声明或复合字面量时,都会执行初始化;如果使用了constexpr,那么初始化器会在翻译期求值一次,而在每次执行到该处时,新实例都会被初始化为这个固定值;否则,每次执行到该声明时,对象的表示都会重新变为不确定。对这类具有变长数组类型的对象,其生存期从对象声明处开始,到程序执行离开该声明的作用域时终止。26)如果该作用域被递归进入,则每次都会创建该对象的一个新实例。对象的初始表示是不确定的。
脚注说明
24)“恒定地址”是指:在可能不同时间构造出的两个指向该对象的指针会比较相等。该地址在同一程序的两次不同执行中可以不同。
25)若对象具有 volatile 限定,则最后一次存储不要求必须在程序中显式写出。
26)离开包含该声明的最内层块,或者跳转到该块或其内嵌块中位于该声明之前的位置,都算离开该声明的作用域。