内存模型和名称空间
2020-02-24 10:37:50 6 举报
AI智能生成
C++ plus
作者其他创作
大纲/内容
名称空间//331后未看
问题
名称冲突增加,很多程序的名称是一样的。
作用
控制名称的作用域
传统的C++名称空间
相关概念
声明区域
含义
可以在其中声明的区域。<br>在函数外面声明全局变量——声明区域为其声明所在文件<br>函数中——代码块
潜在作用域
含义
声明点——声明区域结尾
作用域
含义
变量对程序可见的范围
有时全局变量会被局部变量隐藏
新的名称空间特性
新增的功能
通过定义一种新的声明区域来创建命名的名称空间
好处
名称空间之间相同的变量名称不会冲突
允许程序的其他部分使用该名称空间中声明的东西
创建名称空间
格式
namespace Jack{<br> double pail; //变量<br> void fetch{};//函数<br> int pal;<br> struct Well{....};//结构<br>}
没有分号
说明
名称空间可以全局,也可以位于另个一个名称空间中,<br>不能位于代码块中//??<br>所以,名称空间中声明的名称链接性是外部(除非它定义了常量//???)
不能位于代码块中,意思是不能位于函数中<br>
名称空间类型
用户自定义
全局名称空间
对应于文件级声明区域,<br>前面所说的全局变量在全局名称空间中
???什么东西 ,那std 是什么名称空间
加入新名称
格式
namespace Jack{<br> char * goose(const char *);<br>}
在那里定义名称空间?哪里加入新的名称??这样加入不会乱吗??
因为名称空间开放性,可以在后续加入。
函数定义
在Jack中 有fetch函数,在Jack中提供函数代码<br>namespace Jack{<br> void fetch()<br> {<br> ......<br> }<br>}
没有分号,在名称空间中提供的函数要<br>写函数地冠以
访问名称空间的名称
方法
作用域解析<br>::运算符
Jack::pail
using 声明
using Jack::pail;<br>
using 编译指令
using namespace Jack;
说明
用using 声明,using编译指令会增加名称冲突性
using Jack::pal;<br>using Jill::pal;<br><br>pal = 4; //not allow
using声明
位置
局部引用名称空间的名称
namespace Jill{<br> ....<br> double fetch<br>}<br>char fetch;<br>int main()<br>{<br> using Jill::fetch;<br> double fetch; //不允许<br> cin>>fetch; //隐藏全局变量fetch<br> cin>>::fetch;//引用全局变量<br>}
说明
::pail表示用全局名称空间的全局变量
全局引用
using Jill::fetch;//在以后函数中,fetch都有作用<br>int main<br>{<br>....<br>}
using编译
位置
局部引用名称空间的名称
namespace Jill{<br> ....<br> double fetch<br>}<br>char fetch;<br>int main()<br>{<br> using namespace Jill;<br> double fetch; //允许<br> cin>>fetch; //隐藏全局变量fetch,Jill中的fetch<br> cin>>Jill::fetch; <br> cin>>::fetch;//引用全局变量<br>}
子主题
using 声明,编译的区别
声明
using Jill::fetch;<br>double fetch;//not allow
double fetch;<br>using Jill::fetch; //not allow<br>
编译
using namespace Jill;<br>double fetch;//可以,局部隐藏名称版本
可以
使用声明<br>原因
声明比编译指令更加安全。如果名称与局部名称发生冲突,会报错。
名称空开放性,使名称空间的名称可能分散在各处
尽量使用 ::运算符和声明
其他
include<iostream.h>可代替 include<iostream> using namespace std;
iostream.h没有使用名称空间std
名称空间特性
开放性
嵌套性
名称空间中创建<br>名称空间
例子
namespace elements<br>{<br> namespce fire<br> {<br> int flame;<br> }<br>}
访问嵌套的元素
flame
elements::fire::flame
只能这样写吗???
using elements::fire::flame;<br>flame直接用
using namespce elements::fire;<br>flame (直接用)
名称空间中<br>使用using 编译<br>指令,声明
例子
namespace myth<br>{<br> using Jill::fetch;<br> using namespace elements;<br> using std::cout;<br> uing std::cin;<br>}
访问嵌套的元素
fetch
myth::fetch
Jill::fetch
using namespce myth;<br>fetch;
可传递
含义
using namespace myth<br>=<br>using namespace myth;<br>using namespace elements;
创建名称空间别名
格式
namespace myth{。。。}是名称空间
namespce m=myth;
给在名称空间定义的<br>名称空间改别名
namespce MEF=myth::elements::fires;
未命名的名称空间
格式
namespace <br>{<br> int ice;<br> ...<br>}
作用
代替链接性为内部的静态变量
<b>static int counts;</b><br>int other();<br>int main()<br>{<br>...<br>}<br>int other()<br>{<br>...<br>}
<b>namespace<br>{<br>int counts;<br>}</b><br>int other();<br>int main()<br>{<br>...<br>}<br>int other()<br>{<br>...<br>}
有名称的要使用using ...???
名称空间实例
p331程序9.11
好好揣摩。
名称空间的作用
第二个源代码文件可以不是放main ,<br>只放名称空间的函数定义。在头文件中,<br>名称空间只能放函数原型?
一定要导入名称空间最初的创建才可以吗?
名称空间及其前途
p334
单独编译
含义
将组件函数放在独立的文件中。单独编译这些文件,<br>将它们链接成可执行的程序
翻译单元 就是 文件
好处
管理便捷
程序分成三个文件
头文件
一般包含的内容
函数原型
使用#define 或 const 定义的符号常量
结构声明
类声明
模板声明
内联函数
代码
代码
子主题
说明
包含头文件时候应该用"coordin.h"不是<coordin.h>
""
编译器首先查找当前的工作目录或源代码目录(或其他,取决于编译器)。<br>如果没有找到头文件,再标准位置查找
<>
编译器在存储标准头文件的主机系统的文件系统中查找
一个文件只能包含同一个头文件一次,但是可能使用另一个 包含了同一个头文件 的头文件。<br>用基于预处理编译指令#ifndef。<br>#ifndef COORDIN_H_ <br>...<br>#endif<br>意味仅当以前没有使用预处理器编译指令#define 定义名称 COORDIN_H_时,才处理#ifndef 和#endif之间的语句<br>(#ifndef COORDIN_H_ 下面的 #define COORDIN_H_ 的作用是这样)
注意
不要把<b>函数定义和变量声明</b>放在头文件中
源代码文件
内容
包含与结构有关的函数的代码
一般只是一个main函数
代码
代码
说明
注意
如果只有源代码文件1,2没有头文件。需要在两个文件前部都加上头文件的的东西。<br>例如都要加上同一个函数原型
组合原理
书p302
怎么在一起编译链接???
执行编译命令??
注意
不同编译器有不同的名称修饰。要确保在链接时,<br>所有文件对象或库都是由同一个编译器生成
存储持续性、作用域和链接性
存储数据方式
持续性
自动存储持续性
有两种变量
静态存储持续性
3种变量
线程存储持续性
动态存储持续性
作用域
链接性
总结(图)
<table border="1"><tbody><tr><td><span><strong><span>位置</span></strong></span></td><td><span><strong><span>持续性</span></strong></span></td><td><span><strong><span>链接性</span></strong></span></td><td><span><strong><span>作用域</span></strong></span></td></tr><tr><td><span><span>函数定义<span>内</span>声明的变量 (自动变量)(关键字<span>auto</span>)</span></span></td><td><span><span>自动</span></span></td><td><span><span>无链接性</span></span></td><td><span><span>局部</span></span></td></tr><tr><td><span><span>函数定义<span>内</span>,并且使用<span>static</span>声明</span></span></td><td><span><span>静态</span></span></td><td><span><span>无链接性</span></span></td><td><span><span>局部</span></span></td></tr><tr><td><span><span>函数定义<span>外</span>,并且使用<span>static</span>声明(或<span>const</span>)</span></span></td><td><span><span>静态</span></span></td><td><span><span>内部</span></span></td><td><span><span>全局</span></span></td></tr><tr><td><span><span>函数定义<span>外</span>声明 (外部变量)</span></span></td><td><span><span>静态</span></span></td><td><span><span>外部</span></span></td><td><span><span>全局</span></span></td></tr><tr><td><span><span>new创建的变量</span></span></td><td><span><span>动态</span></span></td><td><span><span> </span></span></td><td><span><span> </span></span></td></tr></tbody></table>
作用域和链接
作用域
描述
名称在文件的多大范围可见
变量类型
局部变量
作用域
只在代码块内起作用
定义方式
在函数中定义的变量
变量类型
变量是静态,或者自动变量
自动变量只能是局部变量。
全局变量
作用域
在定义它的位置,到文件结束
定义方式
在函数外部定义的变量
变量类型
变量是静态变量
其它类型作用域
在类中声明的成员的作用于为整个类。<br>
名称空间中声明的变量的作用域为整个名称空间
全局作用域是名称空间作用域的特例???
函数的作用域可以是整个类 或整个名称空间(包括全局的)
链接性
描述
名称如何在不同的单元(文件)间共享
链接为外部的名称——在文件间共享
如果在其他文件中再次引用变量,要再次引用声明,格式:extern int a;(不能初始化)
链接为内部的名称——只在一个文件中共享,要加static
注意
自动变量没有链接性
自动存储持续性
声明位置
在函数中声明
在函数中声明的变量默认为自动变量,局部变量
注意
在函数中的代码块内<br>和非代码块内同时声<br>明同一个变量
<div>{</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>int teledeli;</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>...</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>....</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>{</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>int teledeli; //外部的teledeli被隐藏 </div><div><span class="Apple-tab-span" style="white-space:pre"> </span>...</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>}</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>...</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>...</div><div>}</div>
作用域
局部变量
整个函数中
代码块内
如果变量在函数中的代码块中声明
链接性
无链接性
自动变量和栈
自动变量<br>管理方法
留出一段内存,视为栈,管理变量的增减
栈的原理
书p308图
说明
只是移动指针的位置,没有删除内存中的数据
寄存器变量
register int count_fast
说明
register在C++11不表示变量使用CPU寄存器来存储自动变量
在C++11 register的意思是,变量为自动变量 ,与原来的auto用法完全相同
保留关键字register原因,避免使用了该关键字的现有代码非法
静态持续变量
连接性类型
外部~
内部~
无链接性
持续性
整个程序执行期间存在,不论是有无链接性,链接性是什么
存储位置
分配固定的内存块存储所用的静态变量
创建
链接性外部
int global = 100;<br>int main()<br>{<br> .......<br>}
简称外部变量
链接性内部
static int global = 100;<br>int main()<br>{<br> ...<br>}
无链接性
int main()<br>{<br> static n=100;<br>}
子主题
说明
自动初始化为0或者'\0'
静态变量初始化
知识
静态初始化在编译器处理文件(翻译单元)时初始化变量
类型
0初始化和常量表达式初始化——静态初始化
例子
int x;<br>int y = 5;<br>long z = 13*13;
静态初始化可以适用于自动变量吗??
动态初始化在编译后初始化
例子
const double pi = 4.0*atan( 1.0 );
静态持续性,外部链接性
变量特点
链接性为外部的变量称为外部变量。也是全局变量。<br>在不同文件中可以共享,但是要有一定的格式说明共享。
单定义规则
含义
变量只能有一次定义//??
程序中可包含多个同名变量,但是每个变量都只有一个定义。<br>//但是不能同时定义同一名称的外部变量?<br>//一个全局,一个局部可以。<br>//两个都是局部,但处于不同代码块可以。
<span style="color: rgb(51, 51, 51); font-family: 'Microsoft Yahei', arial, sans-serif; font-size: 14px; line-height: 20px; white-space: pre-wrap;">如果一个程序包含两个文件,在两个文件中都要用到同一个外部变量Num,不能分别在两个文件中各自定义一个外部变量Num,这样会引发“重复定义”错误</span>
变量声明方式
定义声明
简称定义
特点
给变量分配存储空间
格式
引用声明
简称声明
特点
不给变量分配存储空间,引用的是已有的变量//??
好像与以前的不同,定义声明在开头??引用声明在后面??
格式
extern int cats;
说明
有extern 且不能初始化。虽然要把file01 fle02链接在一起,<br>但在file02中使用cats ,也要引用声明后才能用
//file01.cpp<br>extern int cats =20; //有extern 但是初始化了,是定义声明,分配存储空间。<br>int dogs = 22 ;//定义声明<br>int flease; //定义声明<br><br>//file02.cpp<br>extern int cats; // 有extern ,是引用声明,用的是file01中的cats<br>extern int dogs;
如果在file02.cpp中让extern int cats = 30 会怎么办?好像会报错,不能定义两次。
在file02中,不可以使用flease,因为没有引用声明
在file02.cpp中引用了01中的cats ,在02中修改cats,01中的cats会相应变化,因为是同一个变量。
外部变量与<br>局部变量
如果cats是全局变量,在函数中也定义了一个cats 的局部变量。在函数中会先隐藏全局的cats,<br>如果要显示全局的cats ,在cats前+::,::cats 即可。
在程序中过多使用全局变量会导致程序不可靠。造成数据的不必要访问,数据完整性可能会被破坏,所以必要时加上const 定义全局变量。(其实是字符常量)
静态持续性、内部链接性
变量特点
只在所属的一个文件中可共享
声明
函数外部,声明变量加static int n;
说明
//file1<br>int errors= 5<br>...<br>//file2<br>int errors =5
不可以,违反单定义规则。<br>最好在编f2的时候,error 的声明 : extern int errors; statics int errors;
//file1<br>int erroes =5<br>...<br>//file2<br>static int errors =5
可以,静态内部变量隐藏常规的外部变量。
静态连续性,无链接性
变量特点
变量时局部变量。只在代码块中可用,但是在代码块不处于活动状态时扔存在。
如果变量是初始化,只会初始化一次。
再次进入函数时,变量的值保持不变。忽视初始化。
声明
在函数中 <br>{<br> static int n = 2;<br> ...<br>}
其它
cin.get( char * ,int )读取空行,cin会是false。<br>int a[n]<br>cin.get(a ,int n )读取一行时,都不够数,后面都会被置于\0?<br>如果满了 ,只读取n-1个数,最后一个设置成\0
说明符和限定符
作用
提供了其它有关存储的信息
存储说明符
内容
auto
C++11中不再是说明符
register
C++11中含义只是说明变量时自动类型
static
extern
thread_local
C++11新增
指出变量的持续性与其所属线程的持续性相同
mutable
说明
只能有一个说明符,但是thread_local 变量除外,它可与static ,extern 结合
cv-限定符
内容
const
volatile
作用//??
即使程序没有对内存单元进行修改,其值也可能发生变化。书p317
mutable
作用
指出,即使结构(或类)变量为const,其某个成员也可以被修改
格式
struct student{<br> char name[20];<br> mutable double score;<br>}<br>const student std1={"Wang",99.0};<br>std1.score = 88//allow
再谈const
对全局变量的影响
int fingers = 10;
外部变量
<b>const int fingers = 10;</b>
全局变量的链接性是内部的。
const int fingers = 10;可以放在头文件中,因为是内部,所以不用担心会重复定义。
const全局变量<br>声明为外部变量
<b>extern const int fingers = 10;</b>
不能放在头文件中。
函数和链接性
函数持续性
静态,整个程序执行期间都一直存在
链接性
默认为外部
可以在函数原型中使用关键字extern指出函数时在另一个文件中定义的。(不过这是可选的??)
在每个文件中,只要使用到函数,直接写上函数原型就可以。
内部链接性
方法
在<b>函数原型和函数定义</b>中使用关键字static
static int private(double x);<br> ...<br>static int private(double x);<br>{<br> ....<br>}
说明
函数只在本文件中适用。
可在其他文件定义同名函数(特征标也一样也可以?),这时会隐藏外部函数
注意
非内联函数定义只有一个。遵守单定义规则。
子主题
C++在哪里查找函数定义
函数是静态
在文件中查找
不是静态
在程序文件中查找(要包括头文件???吗??)找到两个定义,发出错误消息。<br>没有找到,在库中查找。
这样说,好像不用使用头文件。<br>使用某些头文件才能使用一些函数是怎么回事。
如果定义了一个与库相同名字的函数,编译器将使用程序员定义的版本。
语言链接性
含义
问题
c语言链接性与c++语言链接性不同。<br>要在C++程序中使用C库中预编译的函数,产生有问题。
c语言函数名不能相同,C++允许函数重载
方法
在函数原型指出要使用的约定(c还是C++语言链接)
例子
extern "C" void spiff(int); //use C protocol for name look-up
extern void spiff(int);
默认C++
extern "C++" void spiff(int) //use C++
显式指出使用C++语言链接
存储方案和动态分配
编译器使用的内存
静态变量
自动变量
动态变量
动态内存
因素
由运算符new \delete 控制,不是由作用域和链接性控制
注意
float *p_free = new float [20] ;<br>当语句块执行完毕时候,p_free(自动变量)指针消失,<br>但在动态内存上(分配的动态内存)数据一直在内存上,<br>如果想在另一个函数使用动态内存上的数据,需要返回<br>p_free指向的地址。
其实没有动态变量这一说法。P_free是自动变量。给它分配的内存是动态内存。
当p_free 为外部变量的时候,位于该声明之后的函数都可以使用p_free,在其他文件中 :要 extern *p_free 引用声明一下
程序结束时候,由new释放的内存通常会被释放,但是有时也不一定。注意使用了new,就要用delete
new运算符初始化
单变量
float *f = new int (6.0);
括号
列表也可以(不过是C++11内容)
数组、结构
student *ptu = new student {2.5 , 3.5 ,4.5}
l列表C++11
int * ar = new int [4] {1,2,3,4 }
元素表示
ar[1] = 1<br>//把ar看成一个数组就可以
new失败
返回空指针,引发异常 std::bad_alloc
new:运算符、函数和替换函数
new 和new[]调用一下函数
分配函数
void * operator new(std::size_t);
std::size_t 是一个typedef,对应于合适的整数//??
void *operator new [ ] ( std::size_t );
释放函数
void operator delete(void *);
void operator delete [ ]( void *);
作用??表示的含义??
new 转换<br>//??
int *pi = new int
int * pi = new( sizeof(int) )
int *pa = new int [40]
int *pa = new (40*sizeof(int))
delete pi;
delete (pi)
说明
用new 其实调用一个接受一个参数的new()函数
new delete 是可替换函数,可以自定义为new ,delete 提供替换函数。
定位new 运算符
new作用
在堆找到满足要求的内存块
被称为定位new运算符,能够指定要使用的位置
要求
头文件new
定位new工作原理
它只是返回传递给它的地址,并将其强制转化为void * ,以便可以赋给任何指针
格式
student * p1 = new (buffer1) student; #1<br> int *p2 = new (buffer2) int [20];
char buffer1[50];<br>char buffer2[120];<br>....<br>int main<br>{<br> student * p1 = new (buffer1) student;<br> int *p2 = new (buffer2) int [20];<br>}
int *p3 = new(buffer2 +N*sizeof(int )) int [20]#2
说明
#1 表明p1指向buffer1 的内存开头。就算buffer1 是char 类型 ,没有关系。<br>
若int *p2 = new (buffer2) int [20] = {1,2,3,4,5...}, <br>得到p2[0] = 1 ,p2[1] = 2 ,置于buffer1[ 0 ] = 多少就不知道了
注意
delete 只能用于指向常规new 运算符分配的堆内存。<br>buffer 指定的内存是静态内存,所以不可以用<br>delete p2 ;会引发程序错误
定位new其它形式
标准定位New 调用一个接受两个参数的new()函数
int * pi = new (buffer) int ;
int *pi = new( sizeof(int) ,buffer )
定位new函数不可以替换,但可以重载,即使额外的参数没有指定位置。//??
自由主题
0 条评论
下一页