C++ Primer 学习笔记_23_类与数据抽象(9)–四种对象生存期和作用域、static 用法总结
前言:
从上图可知,程序占用的内存被分了以下几部分.
(1)、栈区(stack)
存放函数的参数值,局部变量的值等,内存的分配是连续的。栈上的内容只在函数的范围内存在,当函数运行结束,这些内容也会自动被销毁,其特点是效率高,但空间大小有限
注意:通常栈空间容量比较小,一般是1MB~2MB,所以体积比较大的对象不适合在栈中分配。
(2)、堆区(heap)
,其生命周期由,它们是不同区域的内存块通过指针链接起来的。在没有释放之前一直存在,直到程序结束,其特点是使用灵活,空间比较大,但容易出错。
(3)、静态区(全局区)(static)
。静态区的内容在总个程序的生命周期内都存在,由编译器在编译的时候分配,程序结束后由系统释放。
(4)、文字常量区
常量字符串就是放在这里的。 程序结束后由系统释放
(5)、程序代码区
存放函数体的二进制代码。
一、四种对象生存期和作用域
(1)栈对象
隐含调用构造函数(程序中没有显式调用)
(2)堆对象
隐含调用构造函数(程序中没有显式调用),要显式释放
(3)全局对象、静态全局对象
全局对象的构造先于main函数
已初始化的全局变量或静态全局对象存储于.data段中
未初始化的全局变量或静态全局对象存储于.bss段中
(4)静态局部对象
已初始化的静态局部变量存储于.data段中
未初始化的静态局部变量存储于.bss段中
注意:箭头的方向的意思是,栈是由高地址向低地址扩展,堆是由低地址向高地址扩展
【例子】
#include <iostream>using namespace std;class Test{public:Test(int n) : n_(n){cout << "Test " << n_ << " …" << endl;}~Test(){cout << "~Test " << n_ << " …" << endl;}private:int n_;};int n; // 未初始化的全局变量,初始值为0。n存储于.bss段中。(block started by symbol)int n2 = 100; // 已初始化的全局变量,初始值为100。n2存储于.data段中。Test g(100); // 全局对象的构造先于main函数static Test g2(200);int main(void){cout << "Entering main …" << endl;Test t(10);// 栈上创建的对象,在生存期结束的时候自动释放{Test t(20);}{Test *t3 = new Test(30);// 堆上创建的对象,要显式释放delete t3;}{static int n3;// n3存储于.bss段中 (编译期初始化)static int n4 = 100; // n4存储于.data段中 (编译期初始化)static Test t4(333); // t4对象运行期初始化 .data段}cout << "Exiting main …" << endl;}
运行结果:
Test 100 …Test 200 …Entering main …Test 10 …Test 20 …~Test 20 …Test 30 …~Test 30 …Test 333 …Exiting main …~Test 10 …~Test 333 …~Test 200 …~Test 100 …
二、static 用法总结
(1). 用于函数内部修饰变量,即函数内的静态变量。这种变量的生存期长于该函数,使得函数具有一定的“状态”。使用静态变量的函数一般是不可重入的,也不是线程安全的,比如strtok(3)。(2). 用在文件级别(函数体之外),修饰变量或函数,表示该变量或函数只在本文件可见,其他文件看不到也访问不到该变量或函数。C语言的这两种用法很明确,一般也不容易混淆。
由于C++引入了类,在保持与C语言兼容的同时,static关键字又有了两种新用法:(3).用于修饰类的数据成员,即所谓“静态成员”。这种数据成员的生存期大于class的对象(实例/instance)。静态数据成员是每个class有一份,普通数据成员是每个instance 有一份。(4). 用于修饰class的成员函数,即所谓“静态成员函数”。这种成员函数只能访问静态成员和其他静态成员函数,不能访问非静态成员和非静态成员函数。
1、static在程序中三种用法
(1)static在函数或全局只对当前文件下可见
(2)static在类中只属于一个类而不属于特定对象,或对象的变量和函数
(3)statci在头文件中作用域只在定义了该头文件的c/cpp文件中,其他有同一头文件是不可见的。(在网上看到一个说法,不一定对,这样定义有一定的危害性:头文件包含多次,变量就定义了多少次,容易重复定义,因此不建议在头文件定义static。)
2、不考虑类,static的作用
(1)第一个作用:隐藏
当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。比如,同时编译两个源文件,a.cpp和main.cpp,下面时a.cpp的内容:
这里的风景美不胜收,真让人流连忘返。