2020 我的C++的学习之路 第九章 内存模型与名称空间
以C++ Primer Plus为参考书籍,自身归纳知识点,加深记忆。
内存模型与名称空间
- 存储持续性
- 作用域与链接
- 自动存储持续性
- 静态持续变量
- 静态持续性、外部链接性
- 静态持续性、内部链接性
- 静态持续性、无链接性
- 说明符和限定符
- 存储说明符
- cv-限定符
- 定位new运算符
- 名称空间
- using声明与using编译指令
- 名称空间的其他特性
- 未命名的名称空间
存储持续性
①自动存储持续性:在函数定义中声明的变量的存储持续性为自动,在程序开始执行所属的函数或代码块 时被创建,在执行完函数或代码块时,它们的内存被释放。
②静态存储持续性:在函数定义外定义的变量和使用关键字static定义的变量的存储性为静态,在程序运行的整个运行过程都存在
③动态存储持续性:用new运算符分配的内存一直都在,直到delete或者程序结束为止,这种存储持续性为动态,有时被称为自由存储或者堆
④线程存储持续性(C++11):多核处理器中,让程序能狗将计算放在可并行处理的不同线程中,如果变量是使用关键字 thread_local声明的,则生命周期与所属的线程一样长
作用域与链接
作用域(scope)描述了名称在文件的多大范围内可见
链接性(linkage)描述了名称如何在不同单元间共享
自动存储持续性
①在默认情况下,函数中声明的函数参数和变量的存储持续性都为自动,局部作用域,无链接性。
int main()
{int n = 5;{int n =10;cout<<n;//n=10}cout<<n;//n=10
}
两个n都是局部变量,各自在局部作用域中作用,内部的n=10会隐藏外部n=5的定义,当程序离开内部代码块时,原来的定义又重新可见。
②自动变量被存储在栈中,后进先出,即最后加入到栈中的变量首先被弹出。
③atuo关键字在C语言中用于显式地指出变量为自动存储,但在C++11标准下,atuo改为自动类型推断
④register关键字在C语言中用于寄存器存储自动变量以提高访问速度,但在C++11标准下,register用于显式指出变量为自动存储
静态持续变量
静态存储持续性变量有三种链接性:外部链接(可跨文件访问),内部链接(当前文件访问),无链接(当前函数或代码块访问),这三种链接性在程序执行期间存在,编译器将分配固定的内存存储所有的静态变量,而不是栈。倘若没有显式的初始化静态变量,则编译器默认为0。
//a.cpp
int global = 100;//静态全局变量,外部链接的静态变量
static int n = 90;//内部链接的静态变量
int main()
{...
}void fun1()
{static int cnt = 5;//无链接的静态变量int sa = 0;//自动变量
}
外部链接性静态持续变量:必须在代码块外面声明;
内部链接性静态持续变量:必须在代码块外面声明,并用static限定
无链接性静态持续变量:必须在代码块内部声明,并用static限定
静态持续性、外部链接性
倘若存在另外一个文件b.cpp使用a.cpp中的global变量,那么需要在b.cpp中使用关键字extern且不对global进行定义。
// external.cpp -- external variable
// compile with support.cpp
#include <iostream>
// external variable
double warming = 0.3; // warming defined// function prototypes
void update(double dt);
void local();int main() // uses global variable
{using namespace std;cout << "Global warming is " << warming << " degrees.\n";//0.3update(0.1); // call function to change warming//0.4cout << "Global warming is " << warming << " degrees.\n";//0.4local(); // call function with local warming//0.8 0.4cout << "Global warming is " << warming << " degrees.\n";//0.4// cin.get();return 0;
}
// support.cpp -- use external variable
// compile with external.cpp
#include <iostream>
extern double warming; // use warming from another file// function prototypes
void update(double dt);
void local();using std::cout;
void update(double dt) // modifies global variable
{extern double warming; // optional redeclaration,此处可以省略声明,因为上部声明过一次warming += dt; // uses global warmingcout << "Updating global warming to " << warming;cout << " degrees.\n";
}void local() // uses local variable
{double warming = 0.8; // new variable hides external onecout << "Local warming = " << warming << " degrees.\n";// Access global variable with the// scope resolution operatorcout << "But global warming = " << ::warming;//::作用域解析运算符,放在变量名前面会使用全局版本,故此处应是0.4cout << " degrees.\n";
}
静态持续性、内部链接性
// twofile1.cpp -- variables with external and internal linkage
#include <iostream> // to be compiled with two file2.cpp
int tom = 3; // external variable definition
int dick = 30; // external variable definition
static int harry = 300; // static, internal linkage
// function prototype
void remote_access();int main()
{using namespace std;cout << "main() reports the following addresses:\n";cout << &tom << " = &tom, " << &dick << " = &dick, ";cout << &harry << " = &harry\n";remote_access();// cin.get();return 0;
}
// twofile2.cpp -- variables with internal and external linkage
#include <iostream>
extern int tom; // tom defined elsewhere
static int dick = 10; // overrides external dick//覆盖上部的dick变量,此处为静态内部链接变量
int harry = 200; // external variable definition,// no conflict with twofile1 harryvoid remote_access()
{using namespace std;cout << "remote_access() reports the following addresses:\n";cout << &tom << " = &tom, " << &dick << " = &dick, ";cout << &harry << " = &harry\n";
}
静态持续性、无链接性
无链接性的静态变量用关键词static在代码块中声明,即使该代码块不处于活动状态时,该变量一直存在,并且只在启动一次时进行初始化,以后再调用函数时,该变量不会被初始化
// static.cpp -- using a static local variable
#include <iostream>
// constants
const int ArSize = 10;// function prototype
void strcount(const char * str);int main()
{using namespace std;char input[ArSize];char next;cout << "Enter a line:\n";cin.get(input, ArSize);while (cin){cin.get(next);while (next != '\n') // string didn't fit!cin.get(next); // dispose of remainderstrcount(input);cout << "Enter next line (empty line to quit):\n";cin.get(input, ArSize);}cout << "Bye\n";
// code to keep window open for MSVC++
/*
cin.clear();while (cin.get() != '\n')continue;cin.get();
*/return 0;
}void strcount(const char * str)
{using namespace std;static int total = 0; // static local variableint count = 0; // automatic local variablecout << "\"" << str <<"\" contains ";while (*str++) // go to end of stringcount++;total += count;cout << count << " characters\n";cout << total << " characters total\n";
}
count每次调用都会被初始化为0,而total仅在第一次调用才会被初始化为0,每次调用后都会被存储,从而达到计数累加的效果。
说明符和限定符
存储说明符
①auto(C++11不再是说明符)
②register
③static
④extern
⑤thread_local
⑥mutable(即使结构或类变量为const,但用mutable可以使其声明的成员被修改)
同一个声明中不能使用多个说明符,但thread_local除外,可与static或extern结合使用
cv-限定符
①const
②volatile
关键词volatile表明,即使程序代码没有对内存单元进行修改,其值也可能会发生变化。
在C++中,倘若对全局变量(静态持续性,外部链接)加以const限定,可将该变量的链接性改为内部链接性,也就是说在C++中,全局变量const限定相当于static存储说明。
定位new运算符
通常new负责在堆中找到一个满足要求的内存块,而定位new运算符则可以指定要使用的位置
double *ptr = new double[5];//动态分配内存
struct chaff
{char drss[20];int slag;
}char buffer[500];
chaff *pch;
pch = new (buffer)chaff;//将结构chaff放入指定的buffer内存当中,并分配合适的内存大小
// newplace.cpp -- using placement new
#include <iostream>
#include <new> // for placement new
const int BUF = 512;
const int N = 5;
char buffer[BUF]; // chunk of memory
int main()
{using namespace std;double *pd1, *pd2;int i;cout << "Calling new and placement new:\n";pd1 = new double[N]; // use heappd2 = new (buffer) double[N]; // use buffer arrayfor (i = 0; i < N; i++)pd2[i] = pd1[i] = 1000 + 20.0 * i;cout << "Memory addresses:\n" << " heap: " << pd1<< " static: " << (void *) buffer <<endl;cout << "Memory contents:\n";for (i = 0; i < N; i++){cout << pd1[i] << " at " << &pd1[i] << "; ";cout << pd2[i] << " at " << &pd2[i] << endl;}cout << "\nCalling new and placement new a second time:\n";double *pd3, *pd4;pd3= new double[N]; // find new addresspd4 = new (buffer) double[N]; // overwrite old datafor (i = 0; i < N; i++)pd4[i] = pd3[i] = 1000 + 40.0 * i;cout << "Memory contents:\n";for (i = 0; i < N; i++){cout << pd3[i] << " at " << &pd3[i] << "; ";//pd[3]的地址与pa[1]的地址不一样,重新分配了一块新的地址cout << pd4[i] << " at " << &pd4[i] << endl;//pd[4]的地址与pa[2]的地址一样}cout << "\nCalling new and placement new a third time:\n";delete [] pd1;pd1= new double[N];pd2 = new (buffer + N * sizeof(double)) double[N]; for (i = 0; i < N; i++)pd2[i] = pd1[i] = 1000 + 60.0 * i;cout << "Memory contents:\n";for (i = 0; i < N; i++){cout << pd1[i] << " at " << &pd1[i] << "; ";cout << pd2[i] << " at " << &pd2[i] << endl;}delete [] pd1;//buffer指定的是静态内存,而delete只能用于指向的堆内存,因此不能用deletedelete [] pd3;// cin.get();return 0;
}
名称空间
名称空间可以是全局的,也可以是位于另一个名称空间中,但不能处于代码块中,因此在默认情况下,在名称空间中声明的名称的链接性是外部的。
namespace Jack
{double pail;void fetch();int pal;struct Well{...};
}
namespace Jill
{double bucket(double n){...};double fetch;int pal;struct Hill{...}
}
任何名称空间中的名称都不会与其他名称空间中的名称发生冲突,因此Jack中的fetch与Jill中的fetch共存,Jill中的Hill可以与外部的Hill共存。
名称空间是开放的,可以把名称加入到已有的名称空间中
namespace Jill
{char * goose(const char*);//加入上述的Jill中
}
利用作用域解析运算符::来访问名称空间中的名称,使用名称空间限定该名称:
Jack::pail = 12.34;//赋值
Jill::Hill mole;//结构
Jack::fetch();//函数调用
在名称空间中声明的函数名的作用域为整个名称空间,因此声明和定义必须位于同一个名称空间中。
using声明与using编译指令
using声明:
using Jill::fetch;
using编译指令:
using namespace Jill;
using声明只是让名称空间中的一个名称可用;using编译指令则是可以使用名称空间中的所有名称,可以认为using编译指令中包含了所有名称的using声明。
名称空间的其他特性
可以将名称空间声明进行嵌套:
namespace elements
{namespace fire{int flame;...}float water;
}
倘若要使用fire内部的名称,则using namespace elements::fire;
另外名称空间中也可以使用using编译指令和using声明:
namespace myth
{using Jill::fetch;using namespace elements;using std::cout;using std::cin;
}
倘若要访问fetch,因此可以这样myth::fetch;
,也可以Jill::fetch;
未命名的名称空间
namespace
{int count;
}
未命名的名称空间相当于提供了内部链接性的静态变量。
2020 我的C++的学习之路 第九章 内存模型与名称空间相关推荐
- C++ Primer Plus学习(九)——内存模型和名称空间
内存模型和名称空间 单独编译 存储持续性.作用域和链接性 名称空间 单独编译 程序一般可以分为三部分: 头文件:包含结构声明和使用这些结构的函数的原型: 源代码文件:包含与结构有关的函数的代码: 源代 ...
- C++(学习笔记)内存模型和名称空间
文章目录 前言 一.单独编译 二.存储持续性.作用域.链接性 1.作用域和链接 2.静态持续变量 3.静态持续性.外部链接性 4.静态持续性.内部链接性 5.静态持续性.无链接性 6.const全局变 ...
- C/C++学习之路_七: 内存管理
C/C++学习之路_七: 内存管理 目录 作用域 内存布局 内存分区代码分析 1. 作用域 C语言变量的作用域分为: 代码块作用域(代码块是{}之间的一段代码) 函数作用域 文件作用域 1. 局部变量 ...
- alin的学习之路:共享内存
alin的学习之路:共享内存 1. 概念 共享内存是进程间通信中效率最高的一种方式. 共享内存: 可以被多个进程同时使用的一块内核的内存 有血缘关系的进程 没有血缘关系的进程 这块内存不属于任何的进程 ...
- Cyclone V SoC FPGA学习之路第一章:综述
Cyclone V SoC FPGA学习之路第一章:总体了解 关键词: adaptive logic modules – ALM 自适应逻辑模块 logic array block --LAB 逻辑阵 ...
- Cyclone V SoC FPGA学习之路第二章:硬件篇
Cyclone V SoC FPGA学习之路第二章:硬件篇(内部资源) 前言 上一章了解了<cycloneV device datasheet>,其中数据手册里重点介绍了电源要求,时序参数 ...
- 西瓜书学习笔记第2章(模型评估与选择)
西瓜书学习笔记第2章(模型评估与选择) 2.1经验误差与过拟合 2.2评估方法 2.2.1留出法(hold-out) 2.2.2交叉验证法(cross validation) 2.2.3自助法(boo ...
- JUC进阶之路-Java的内存模型JMM
本文源自转载:JUC进阶之路-Java的内存模型JMM 目录 一.大厂常见的JMM面试题 二.什么是JAVA内存模型JMM(Java Memory Model) 三.JMM的三大特性 3.1 可见性 ...
- 机器学习理论《统计学习方法》学习笔记:第九章 EM算法及其推广
第九章 EM算法及其推广 概述 EM算法 EM算法的收敛性 EM算法实现 K-Means与高斯混合模型 K-Means 高斯混合模型 概述 EM算法是一种迭代算法,1977年由Dempster等人总结 ...
最新文章
- python教学上机实验报告怎么写_Python基础(下)
- Spring Cloud第九篇:链路追踪Sleuth
- windows最重要的三个dll
- 3%7python_Centos7 Python2 升级到Python3
- neatdm路径_扫地机还能这么玩 延时摄影看路径规划
- new 对象时的暗执行顺序
- [01] 四大组件之Activity
- JAVASE1~5补充
- Docker 的部署方式
- 统计过程控制图SPC(2)
- 内网穿透小知识|什么是端口映射?端口映射使用操作指南
- 大批量数据导出到Excel的实现
- oracle数据库写文件,Oracle对操作系统文件的读写操作
- 第2章第5节:文本框的使用:复制和移动文本框 [PowerPoint精美幻灯片实战教程]
- 手把手教你搭建一个属于自己的网站-适合零基础小白,文末附网站模板
- ARM GIC(六) GIC V3 电源/功耗管理 分析笔记。
- 微信无法登陆,您绑定的QQ号疑似被盗解决方案
- python计算1的平方减2的平方加3的平方减4的平方怎么算_墙体的面积怎么算的快?墙的平方快速计算方法...
- 你知道PaaS平台的P有多少种写法?
- MySQl排序,别名
热门文章
- 【Flask】url_for函数
- Wireshark抓取数据包
- OpenSSL“心脏出血”漏洞
- WIN32 Inline HOOK
- androidstuido_schooltest_7_storage
- 2020-12-3(ESP定律脱壳理解)
- C/C++使用socket实现server和client
- 力扣: 88. 合并两个有序数组
- Qt的简单介绍和安装
- 网络实验: 总线型以太网的特性---广播、竞争总线(冲突)