9-内存空间和名称空间
ch9 内存模型和名称空间
9.1 单独编译
运行make时,可以跟踪程序依赖的文件以及这些文件的最后修改时间。# include
处理多个文件声明函数的问题,将程序分成三个部分:
- 头文件:包含结构声明和使用这些结构的函数的原型
- 源代码文件:包含与结构有关的函数的代码;(function)
- 源代码文件:包含调用与结构有关的函数的代码;(main函数)
头文件中常包含的内容:
- 函数原型
- 使用
define
或const
定义的符号常量; - 结构声明
- 类声明
- 模板声明
- 内联函数
注意: 请不要将函数定义或变量声明放到头文件中,通常容易引起混乱。
头文件有两种方式<>和“ ”:
- <corrd.h>:如果文件名包含在尖括号中,c++编译器将在存储标准头文件的主机系统中查找;
- “corrd.h”:如果文件名包含在双引号中,c++编译器首先查找当前的工作目录或源代码目录,如果没有找到,则将在标准位置查找;
9.2 存储持续性,作用域和链接性;
存储类别影响信息在文件夹中的共享,存储方案有以下几种,不同的存储方案影响数据保留在内存中的时间:
- 自动存储持续性:在函数定义中声明的变量的存储持续性为自动的,在程序开始执行其所属的函数或代码块时被创建,在执行完函数代码块时内存被释放
- 静态存储持续性:在函数定义外定义的变量和使用关键字 static定义的变量的存储持续性都为静态。在整个允许过程中都存在
- 线程存储持续性:使用关键字thread_local声明的,其生命周期和所属的线程一样长;
- 动态存储持续性:用new分配的内存将一直存在,直到使用delete运算符将其释放或者程序结束为止。有时也被称为自由存储(free store) 或堆(heap)
9.2.1 作用域和链接
作用域(scope)描述了名称在文件的多大范围内可见
链接性(linkage)描述了名称如何在不同单元间共享。链接性在外部的名称可以在文件夹共享,链接性为内部的名称只能由一个文件中的函数共享。注:自动变量的名称没有链接性,不能共享
9.2.2 自动存储持续性
默认情况下,函数中声明的函数参数和变量的存储持续性为自动,作用域为局部,没有链接性。新的代码块中的定义隐藏了以前的定义,新定义可见,旧定义不可见,在程序离开该代码块时,原来的定义由重新可见。
自动变量的初始化
Int w;
cin >> w;
int z = 3 * w;
自动变量和栈
系统用栈管理自动变量,新的变量被放到上面,当程序使用完成后从栈中删除。程序使用两个指针跟踪栈,一个指向栈底—找到开头的位置,另外指向堆顶—下一个可用的内存单元。
寄存器变量
关键字register,建议编译器使用cpu寄存器来存储自动变量, 旨在提升访问变量的速度:
register int count_fast;
9.2.3 静态持续变量
静态存储持续性变量提供了3钟链接性:
- 外部链接性: 可以在其他文件中访问, 必须在代码块的外面声明它;
- 内部链接性:只能在当前文件中访问,必须在代码块的外面声明它,并使用static限定符;
- 无链接性:只能在当前函数或代码块中访问,必须在代码块的里面声明它,并使用static限定符;
由于静态变量的数目在程序运行期间是不变的,因此程序不需要使用特殊的装置(栈)来管理他们。编译器将分配固定的内存块来存储所以的静态变量,这些变量在整个程序执行期间一直存在。
int global = 1000; // 外部链接, 可以在程序的其他文件中使用它
static int one_file = 50; // 内部链接性void funct1(int n)
{static int count = 0; // 无链接性
}
未被初始化的静态变量所有位都设置为0,这种变量被称为零初始化。
9.2.4 静态持续性,外部链接性
链接性为外部的变量称为外部变量,存储持续性为静态,作用域为整个文件。
单定义规则
变量只能有一次定义,为此c++提供零两种变量声明:
- 定义:给变量分配空间
- 引用声明:不给变量分配空间,引用已有的变量。使用关键字extern,且不进行初始化;
double up; //定义 extern int blem; // 声明 extern char gr = 'z'; // 定义 因为赋值了
如果在多个文件中使用外部变量,只需要在一个文件中包含该变量的定义,但在使用该变量的其它所有文件中都必须使用关键字extern声明它。
定义全局变量和局部变量后,局部变量会隐藏全局变量。程序应该避免对数据进行不必要的访问,就越能保持数据的完整性。通常情况下,应该使用局部变量。外部存储数据尤其适用于常量数据,可以使用关键字const来防止数据被修改。
9.2.5 静态持续性,内部链接性
将static限定符用于作用域为整个文件的变量时,该变量的链接性为内部的,链接性为内部的变量只能在其所属的文件中使用,但常规外部变量都具有外部链接性。
static int count = 10;
9.2.6 静态存储持续性,无链接性
将static限定符应用于在代码块中定义的变量,局部变量的持续性为静态的,无链接性。该变量只能在代码块中使用,但它在代码块不处于活动状态时候仍然存在。适用于再生。程序只在启动的时候进行第一次初始化,之后再调用函数时,将不会再次进行初始化,再之前的基础上进行处理。
9.2.7 说明符合限定符
有些被称为存储说明符或cv-限定符
- auto
- register
- static
- extern
- Thread_local
- mutable
cv-限定符
- const:内存被初始化后,程序代码不得对内存单元进行修改
- volatile:不稳定的,程序代码没有对内存单元进行修改,其值也可能发生变化。该关键字的作用是为了改善编译器的优化能力。将变量声明为volatile,相当于告诉编译器不要进行
mutable
即使结果变量为const,其某个成员也可以被修改。
struct data
{char name[30];mutable int access;
};const data veep = {"Calybornue Coldde", 0};
strcpy(veep.name, "jojn") // not allowed
veep.access++; //allowed
9.2.8 函数和链接性
在默认情况下,函数的链接性为外部的,即可以在文件间共享,实际上可以在函数原型中使用关键字extern来指出函数是在另一个文件中定义的。还可以使用static将函数的链接性设置为内部的,使之只能在一个文件中使用。单定义规则也适用于非内联函数,因此对于每个非内联函数,程序只能包含一个定义。
c++在那里查找函数
- 如果该文件中的函数原型指出该函数是静态的,则编译器将只在该文件中查找定义,否则将在所有程序文件中查找
- 如果找到两个定义,则报错
- 如果在程序文件中没有找到,编译器将在库中搜索
9.2.9 语言链接性
编译器执行名称矫正或者名称修饰,为重载函数生成不同的符号名称。可能将spiff(int) 转换成_spiff_i,将spiff(int, int) 转化成_ _spiff_i_i
9.2.10 存储方案和动态分配
使用c++运算符new分配内存,这种内存被称为动态内存。动态内存由new和delete控制。与自动内存不同,动态内存不是LIFO,其分配和释放顺序要取决于new和delete在何时以何种方式被使用。
使用new运算符初始化
如果腰围内置的标量类型分配存储空间并初始化,可在类型名称后面加上初始值
int * pi = new int (6); // set *pi = 6 double * pd = new double (99.9); // set *pd to 99.9struct where {double x;double y;double z; }; where * one = new where {2.5, 5.3, 7.3};
new失败
失败时,早期会返回空指针,但现在会报异常 std::bad_alloc
new: 运算符 函数和转换函数
运算符new和new [] 分别调用以下函数:
void * operator new(std:size_t); // used by new void * operator new[](std:size_t); // used by new[]void operator delete(void *); void operator delete[](void *);
上述函数被称为分配函数(alloction function),位于全局名称空间中。同样有delete和delete[]调用的释放函数。
定位new运算符
通常, new负责在堆(heap)中找到一个足以满足要求的内存块。new运算符有一种变体称为定位new运算符(placement) new运算符,能够指定使用的位置。要使用定位运算符,头文件要包含new。
#include <new>// common new int *p1; p1 = new int (6);// placement new int *p2; p2 = new (buffer1) int (10); // 从buffer1中分配空间给p2
9.3 名称空间
在c++中,名称可以是变量、函数、结构、枚举、类以及类和结构的成员。当随着项目的增大,名称相互冲突的可能性也增加。c++标准提供了名称空间工具,以便更好地控制名称的作用域。
9.3.1 传统的c++名称空间
- 声明区域:声明区域可以在其中进行声明的区域,例如可以在函数外面声明全局变量等。
- 潜在作用域:变量的潜在作用域从声明点开始,到其声明区域的结尾。
- 作用域:变量对程序而言可见的范围
9.3.2 新的名称空间特性
通过定义一种新的声明区域来创建命名的名称空间,目的是提供一个声明名称的区域。一个名称空间中的名称不会与另外一个名称空间的相同名称发生冲突。同时允许程序的其它部分使用该名称空间中声明的东西。
Namespace Jack{
double pail;
void fetch();
int pal;
struct Well{
…;
}
}
默认情况下,在名称空间中声明的名称的链接性为外部的。
通过作用域解析运算符::
使用名称空间来限定该名称:
Jack::pail = 12.34;
- using 声明和 using编译
不希望每次使用名称时候都对它进行限定,c++提供了两种方式进行简化使用:
- using声明:
using Jack::pail
, 一个变量可用 - using编译:
using namespace Jack
, 该名称空间中所有名称都可用 - 一般来说,使用using声明比using编译指令更加安全
总结
- 使用在已命名的名称空间中声明的变量,而不是使用外部全局变量
- 使用在已命名的名称空间中声明的变量,而不是使用静态全局变量
- 如果开发了一个函数库或者类库,应该将其放在一个名称空间中
- 不要在头文件中使用using编译指令
- 导入名称时,首选使用作用域解析运算符或using声明的方法
- 对于using声明, 首选将其作用域设置为局部而不是全局
- 使用头文件来定义用户类型,为操作用户类型的函数提供函数原型
- 将函数定义放在一个独立的源代码文件中
- 头文件和源代码文件一起定义和实现用户定义的类型及其使用方式
- 将main和其它使用这些函数的函数放在第三个文件中
9-内存空间和名称空间相关推荐
- static在内存层面的作用_「C++ Primer plus 心得」9.内存模型和名称空间
本章内容包括: 单独编译 存储持续性.作用域和链接性 定位new运算符 名称空间 C++ 为在内存中存储数据方面提供了多种选择.可以厅数据保留在内存中的时间长度(存储持续性)以及程序的哪一部分可以访问 ...
- 2020 我的C++的学习之路 第九章 内存模型与名称空间
以C++ Primer Plus为参考书籍,自身归纳知识点,加深记忆. 内存模型与名称空间 存储持续性 作用域与链接 自动存储持续性 静态持续变量 静态持续性.外部链接性 静态持续性.内部链接性 静态 ...
- 《C++ Primer Plus》读书笔记之七—内存模型和名称空间
第九章 内存模型和名称空间 1.不要将函数定义或者变量声明放到头文件中. 2.头文件常包含的内容:函数原型.使用#define或者const定义的常量.结构声明.类声明.模板声明.内联函数. 3.避免 ...
- C++ Primer Plus学习(九)——内存模型和名称空间
内存模型和名称空间 单独编译 存储持续性.作用域和链接性 名称空间 单独编译 程序一般可以分为三部分: 头文件:包含结构声明和使用这些结构的函数的原型: 源代码文件:包含与结构有关的函数的代码: 源代 ...
- C++(学习笔记)内存模型和名称空间
文章目录 前言 一.单独编译 二.存储持续性.作用域.链接性 1.作用域和链接 2.静态持续变量 3.静态持续性.外部链接性 4.静态持续性.内部链接性 5.静态持续性.无链接性 6.const全局变 ...
- 【C++ Primer Plus】第9章 内存模型和名称空间
9.1 多文件程序 一个文件(头文件)包含了用户定义类型的定义:另一个文件包含操纵用户定义类型的函数的代码.这两个文件组成了一个软件包,可用于各种程序中. 头文件中常包含的内容: 函数原型. 使用#d ...
- python全局名称空间_python名称空间,命名空间
全局名称空间:在python解释器开始执行之后, 就会在内存中开辟一个空间, 每当遇到一个变量的时候, 就把变量名和值之间的关系记录下来, 但是当遇到函数定义的时候, 解释器只是把函数名读入内存, 表 ...
- 第9章 内存模型和名称空间
待定 本章内容: 单独编译 存储持续性.作用域和链接性 定位(placement)new运算符 名称空间 9.1 单独编译 9.2 存储持续性.作用域和链接性 9.2.4 静态持续性. ...
- C++ Primer Plus 第九章答案 内存模型和名称空间
9.5复习题 //1 homer将自动成为自动变量 在一个文件中将secret定义为外部变量,并在第二个文件中使用extern声明它 在外部定义前加上关键字static,将topsecret定义为一个 ...
最新文章
- boost::asio::streambuf 基本用法和注意事项
- 【CyberSecurityLearning 42】日志记录规则
- php测试代码执行时间,php debug记录程序执行时间和执行情况
- C语言中的“三字母词”坑了工程师
- java 在主方法中定义两个变量 调用方法进行加10_计算机考试二级考试Java模拟试题附答案...
- cesium 知乎_Cesium 源码笔记[2] CesiumWidget模块的实例化过程 ver1.67
- linux经典命令-Web服务器管理
- [zz]linux之sed用法
- 阿里云云计算 48 云安全中心
- 安卓游戏源码-android游戏源码开发-android游戏开发
- android 集成x5内核时 本地没有,腾讯X5内核集成一些建议和爬坑记录
- soapui连接oracle,myeclipse 安装soapui插件
- NBA数据分析及可视化BI数据大屏 (Kobe·Bryant)
- LARS算法---十折交叉验证
- 新书推荐——Linux系统管理与服务器配置
- java项目-第90期基于ssm的嘟嘟二手书商城系统
- Python matplotlib label设置斜体字符
- 系统桌面常见问题处理
- What is 虫洞攻击?
- bzoj 2959: 长跑(LCT+并查集)
热门文章
- EMC测试不合格,应该这样整改
- python nonzero()函数的用法
- Nexus5X Android 安卓 6.0 刷 8.0.1 root
- 全新升级ADS-B地面接收机室外机 pingStation3
- 一个计算机高手的成长——推荐一读
- Python3.7版---双人联机雷霆战机(2D特效+音效+道具+Linux系统)
- iOS 高德地图定位并进行周边搜索
- H5自适应图片-picture标签实现
- activiti 子流程
- oracle旬统计,oracle获取上一旬的开始时间和结束时间的函数