7.5局部对象
在C++语言中,对于每一个变量和对象,都有其各自的作用域和生存期,这两个概念一个是空间的,一个是时间的。对象的作用域指的是该变量的程序文本区,对象的生存期则是程序执行过程中对象存在的时间。
7.5.1自动对象
只有当定义它的函数被调用的时候才存在的对象称为自动对象,自动对象在每次调用函数时创建和销毁。
局部变量所对应的自动对象在函数控制经过变量定义语句时创建。如果在定义时提供了初始化,那么每次创建对象时,对象都会被初始化为指定的初值。对于未初始化的内置类型局部变量,其初值是不确定的随机值(当然这里的随机指的是伪随机)。当函数调用结束时,自动对象就会被撤销。
7.5.2 静态局部对象
一个变量如果位于函数的作用域内,但生存期却跨越了这个函数的多次调用,这种变量往往很有用,则应该讲这样的对象定义为static。
static局部对象确保不迟于在程序执行流程第一次经过该对象的定义语句时进行初始化。这种对象一旦被创建,在程序结束前都不会被撤销。看下面的这个例子,这个函数计算了自己被调用的次数:
#include <iostream> using namespace std; size_t count_calls() { static size_t ctr = 0; return ++ctr; } int main() { for(int i = 0; i < 10; i++) { cout << count_calls() << endl; } return 0; }
程序执行结果:这个程序一次输出1到10(包括10)的整数。
问题与解决
第一次读到上面的程序的时候,有一点疑问:上面的那句话static size_t ctr = 0会不会在每次调用函数的时候把ctr弄成0呢?
当然答案是不会的,不然这个static不就等于不写了吗?
这里还是要搞清楚一个概念,那就是变量的初始化和赋值两种不同的操作。任何变量的初始化都只有一次,就是在变量定义的时候,也就是内存刚刚分配之后的瞬间;赋值操作是修改变量内原来的值(里面的值可能是初始化得到的,也可能是上次赋值得到的)。
静态全局变量就是在main函数调用之前调用的。
静态局部变量则在第一次使用之前调用的。
静态变量的初始化是在首次执行到初始化语句时间执行的,编译时在初始化语句之前放置一个标志位,每次进行判断,倘若需要初始化则执行初始化操作,否则不执行。上面的那句static size_t ctr = 0就是静态局部变量的初始化,只是在第一次调用这个函数,初始化这个静态对象的时候才会被执行,后面的其他次的调用该函数是不会执行这句话的。
那么为什么普通局部变量在每次函数调用的时候都要执行size_t ctr = 0这句话呢?(假设这个函数中有这么一句话)因为它是普通的局部变量,上次的已经被销毁了,这次是重新开辟的内存空间,要对新的内存空间也就是对象进行初始化。而静态局部对象在上次调用之后没有被销毁,所以这次调用不会分配内存空间,当然不用执行初始化的语句了。
实例展示
下面的四个函数,不同的地方仅仅差别在于定义的变量的属性(是不是static)和有没有初始化。
static int ctr = 0仅仅起的是一个初始化的作用,在若干次执行test1()函数时,static int ctr = 0;只在第一次test1()函数被调用的时候初始化为0,当test1()第二次或更多次被调用时,ctr为保存的上一次的值。
#include <iostream> using namespace std; void test1(void) { static int ctr = 0; //静态变量,初始化为0 cout << "ctr1_1:" << ctr << endl; ++ctr; cout << "ctr1_2:" << ctr << endl; } void test2(void) { int ctr = 0; //非静态变量,初始化为0 cout << "ctr2_1:" << ctr << endl; ++ctr; cout << "ctr2_2:" << ctr << endl; } void test3(void) { static int ctr; //静态变量,未初始化 cout << "ctr3_1:" << ctr << endl; ++ctr; cout << "ctr3_2:" << ctr << endl; } void test4(void) { int ctr; //非静态变量,未初始化 cout << "ctr4_1:" << ctr << endl; ++ctr; cout << "ctr4_2:" << ctr << endl; } int main() { for(int i = 0; i < 4; i++) { test1(); test2(); test3(); test4(); cout << "--------------" << endl; } return 0; }
程序执行结果: