什么是存储期?
C++ 中存储期是用户声明对象的属性之一;
用户声明:声明一个名字,在声明过程中关联程序中声明指定的实体,如声明一个变量、函数,类,模板、命名空间等等;
所有的名字都在某段时间驻存在内存中,存储期代表声明的名字在内存中驻存的时期,程序只能在名字的存储期中引用该名字;
存储期类别
存储期分为:
- 自动存储期
- 静态存储期
- 线程局部存储期
- 动态存储期
自动存储期
自动存储期在对象的声明点开始分配,在对象所在块作用域结束时,解分配,所有局部对象,只要没有使用声明说明符static、extern、thread_local都具有自动存储期,典型的拥有此存储期的对象为局部变量,局部类;
自动存储期对象在栈上分配内存。
静态存储期
静态存储期在程序开始执行时分配,在程序结束时解分配,一个对象仅存在一个实例(不然会重定义),所有声明在命名空间中的对象都具有静态存储期,另外,使用声明说明符static/extern也具有静态存储期。
静态存储期变量应该在静态存储区分配。
线程局部存储期
具有线程局部存储期的对象,在每一个线程都有一个独立的实例(包括主线程),他在线程开始是进行分配,在线程结束时解分配。唯有使用声明说明符thread_local声明的对象拥有此存储期。
template <class T> struct S {
thread_local static int tlm;
}
template<> thread_local int S<float>::tlm = 0;
动态存储期
对象的存储是通过使用动态内存分配函数来按请求进行分配和解分配的;
存储类说明
静态局部变量
指定说明符static
且声明于块作用域的变量有静态存储期但是在第一次控制经过它们的声明时初始化(除非初始化为zero-或constant-initialization,它们可能在第一次进入块之前执行)。在之后的所有调用中,声明都被跳过。
块作用域静态变量的析构函数在进程退出时调用,但是仅当初始化成功时执行。
在相同内联函数(可能为隐式内联)的所有定义中的函数局部静态对象都引用自定义于一个翻译单元的同一对象。
链接性 (Linkage)
指代对象,引用,函数,类型,模板,命名空间,或值的名字,都可能有链接性。如果一个名字具有链接性,它涉及其他作用域声明引入的有相同名字的相同实体。如果一个变量,函数,或者其他实体,具有相同的名字,但是时在几个作用域中声明的,且并没有对应的链接性,将会产生几个实体的实例。
无链接性 (no linkage)
无链接性的名字仅在它所在的作用域被引用。
声明在块作用域 (block scope) 的下述名字有无链接性:
- 没有显式声明为
extern
的变量 (无论是否有static
); - 局部类和它们的成员函数;
- 声明在块作用域的其他名字,例如 typedefs,enumerations, 和 enumerators;
没有使用 extern
, module
(since C++20) 或者 内部链接性说明的名字也为无链接性,无论它们在什么作用域中声明。
无链接性意味着作用域外不可见 (没有权限访问)
内部链接性 (internal linkage)
有内部链接性的名字能够被当前翻译单元的所有作用域访问。
声明在命名空间中的下述名字具有内部链接性:
- 声明为
static
的变量,变量模板(since C++14),函数,或函数模板; - non-volatile non-template (since C++14) non-inline (since C++17) non-exported (since C++20) const-qualified 变量 (包括
constexpr
) 没有声明extern
,也没有在之前声明外部链接属性; anonymous unions
的数据成员。
另外,所有声明在unnamed namespace
或 unnamed namespace
中的命名空间,即使它被显式声明为extern
,也具有内部链接性。(since C++11)
在翻译单元范围内可见。
为什么命名空间的const常量具有外部链接属性
外部链接性 (external linkage)
有外部链接性的名字能在其他翻译单元的作用域中引用。变量和函数有外部链接性也有语言链接性 (lanuage linkage),这可以使它能够链接使用不同编程语言书写的翻译单元。
除了上述提到的,声明在命名空间中的下述名字都有外部链接性:
- 上述未列出的变量和函数 (即为,没有声明static的函数,命名空间作用域 non-const变量,没有声明static,任何声明
extern
的变量); - enumerations;
- 类名,它们的成员函数,静态数据成员 (const or not),嵌套类和枚举变量,第一次引入的类体内友元函数。
- 上述未列出的所有模板的名字 (即,未声明static的函数模板)
首次在块作用域声明的下述名字,有外部链接性:
- 变量名声明为
extern
- 函数名
内部/外部链接性总结
内部链接性
- 所有的声明
- 命名空间中的静态函数,静态友元函数,静态变量的定义
- enum定义
- inline函数定义
- 类的定义
- 命名空间中的const常量定义
- union的定义
外部链接性
- 非static的全局变量和全局函数。
- 类中非inline函数,包括类成员函数和类静态成员函数。
- 类静态成员变量
- 命名空间中的非静态函数,非静态友元函数和非静态变量。