C++内存模型
存储持续性
C++存储持续性有以下类别:
- 自动存储持续性:在函数定义中声明的变量(包括函数参数)。
- 静态存储持续性:在函数定义外定义的变量和使用关键字static定义的变量。
- 线程存储持续性(C++11):使用关键字thread_local定义的。生命周期与线程一样长。
- 动态存储持续性:使用new运算符分配的内存将一直存在,直到使用delete运算符将其释放或程序结束为止。有时被称为自由存储/堆。
内存分配位置
-
自动存储变量:分配到栈中,在程序执行其所属的函数/代码块时被创建,执行完函数/代码块时所使用的内存被释放。
-
静态持续变量:分配到内存中固定位置,在程序整个运行过程中都存在。
int global = 300; // static duration, external linkage static int one_file = 50; // static duration, internal linkage void funct1() { static int count = 0; // static duration, no linkage }静态持续变量首先会被初始化为0,若有显示初始化,然后再进行静态初始化(编译器根据文件按内容算出值进行初始化)或动态初始化(编译后在初始化,通常是调用了函数)。局部静态持续变量并非像自动存储变量那样,它只初始化一次。
链接性
链接性为外部的变量称为外部变量,它们的存储持续性为静态。根据单定义规则,使用变量前需要声明,但只能定义一次。使用外部变量的文件中,必须先声明它,声明可分为两种:
- 引用声明/声明:不给变量分配存储空间,因为它引用已有的变量。使用extern关键字,且不进行初始化,否则为定义声明,导致分配存储空间。
- 定义声明/定义:他给变量分配存储空间。
如下示例,file01.cpp中全为定义,file02.cpp与file03.cpp全为声明。
// file01.cpp
extern int cats = 20;
int dogs = 22;
int fleas;
// file02.cpp
extern int cats;
extern int dogs;
// file03.cpp
extern int cats;
extern int dogs;
extern int fleas;
注意:const修饰的外部变量的链接性为内部,可再次使用extern关键字将其变为外部。
extern const int states = 50;
作用域
- 自动存储变量:声明处到代码块结束。
- 静态存储变量:开头为声明处,若为外部链接和內部链接则结尾是文件末尾,若为无链接则结尾是代码块结束。
注意作用域可能会被同名的”相对局部变量“隐藏。
// file01.cpp
int errors = 20;
// file02.cpp
static int errors = 25;
void f()
{
int errors = 30;
}
对于函数
函数的存储持续性都自动为静态,默认下链接性为外部,但可使用static关键字来修改为内部,使之只能作用于该文件。
static int private();
static int private()
{
...
}
内联函数不受单定义规则,意味着内联函数可放在头文件中被不同文件包含,各文件中均有定义,然而C++要求所有内联定义必须相同。
C++寻找函数的顺序:static函数在本身文件中寻找,否则先去所有程序文件中寻找,未找到去库文件中寻找。