第九章 内存模型和名称空间
9.1单独编译
1.程序组成
(1)头文件:存放结构声明、函数原型
(2)源代码文件:与结构有关的函数代码(处理结构)
(3)源代码文件:调用与结构有关的函数的代码
2.头文件应该存放
(1)使用 #define
或 const
定义的符号常量
(2)结构声明
(3)类声明
(4)模板声明
(5)函数原型
(6)内联函数
3.头文件<> 与 ""区别
<>:优先在存储头文件的主机系统的文件系统进行查找;
“”:优先在当前工作目录或源代码目录中查找;
4.避免多次包含同一文件技巧
#ifndef COORDIN_H_
#define COORDIN_H_
...
#endif
9.2存储持续性、作用域和链接性
1.局部变量、静态变量、全局变量、动态内存变量
变量类型 | 存储时间 | 作用域 | 链接性 | 内存位置 | 关键字 |
---|---|---|---|---|---|
局部变量 | 块内 | 块内 | 内部 | 栈 | 无/register |
局部静态变量 | 程序运行期间 | 块内 | 内部 | 全局区 | static |
全局静态变量 | 程序运行期间 | 当前文件 | 内部 | 全局区 | static |
全局变量 | 程序运行期间 | 多个文件 | 外部 | 全局区 | 声明时使用extern |
动态内存变量 | - | - | - | 堆 | new /delete |
注: 变量隐藏:局部变量会隐藏掉全局变量;静态变量隐藏常规外部变量;等
**链接性:**描述名称在不同单元间的共享,包含内部和外部;
内部:表示单个文件的函数共享;
外部:表示可在文件间共享;
内部链接性:表示每个文件都可以拥有一组属于自己的常量;
链接性与作用域表示的涵义一致:内部 <-> 当前文件; 外部 <-> 多个文件;
2.说明符和限定符
说明符 | 涵义 |
---|---|
auto | (C++11中)自动类型推断 |
register | 显示指出局部变量 |
static | 静态变量 |
extern | 声明引用在其他地方定义的变量 |
thread_local | 指出变量的持续性与所属线程的持续性相同 |
mutable | 指出即使结构(或类)变量为const,其某个成员也可被修改 |
注:
1)全局const定义等同于static;例const int fingers = 100;
(内部性链接)
2)extern可覆盖全局const定义;例extern const int fingers = 100;
(外部性链接)
3.函数和链接性
默认情况下,函数的链接是外部的,可多个文件共享;
使用static
可将函数的链接性变为内部,单个文件使用。
4.语言链接性
extern "C"
:使用C语言链接协议
extern "C++"
:使用C++语言链接协议
5.new - 动态内存
1)使用new
运算符初始化:分配内存空间并初始化
例:int *pd = new int(6);
例:where *pd = new where{12.0,13.0,2.5};
(where是strut结构)
2)new失败
发送异常std::bad_alloc
3)new 和 new[]
void * operator new(std::size_t)
void * operator new[](std::size_t)
int *pt = new int;
等价于 int *pt = new int(sizeof(int))
4)定位new运算符
特性:可指定要使用的位置
char buffer[100];
int *p1 = new (buffer) int[20];
释:将p1放到buffer对应的内存位置
注: delete
只能用于常规new运算符分配的堆内存。
9.3名称空间
1.定义
namespace Jack {
double pail;
void fetch();
}
位置:全局 或 另一名称空间中,不可位于代码块中
包含:用户定义的名称空间 以及 全局命名空间(全局变量位于此)
" :: " :作用域解析运算符
1.using声明和using编译指令
1)using声明:由被限定的名称和它前面的关键字using
组成
using Jack::fetch;
2)using编译指令:由名称空间名和它前面的关键字using namespase
using namespace Jack
3)比较:
(1)假设名称空间和声明区域定义了相同的名称:using声明导入,会发生冲突;using编译指令导入,局部变量会将名称空间版本隐藏;
(2)using声明比using编译指令更安全;
2.名称空间的其他特性
namespace myth
{
namespace fire //嵌套
{
int flame;
...
}
using Jill::fetch; //使用using声明
using namespace elements;//使用using编译指令
using std::cout;
}
1)嵌套访问:myth::fire::flame
2)using编译指令可传递
using namespace myth
:就可使用到elements
中的内容
3)别名
namespace MEF = myth::elements;
4)未命名的名称空间 等价于 静态变量
3.示例
namespace Jill{
double bucket(double n){..}
double fetch;
struct Hill{..};
}
char fetch;
int main()
{
using Jill::fetch; //put fetch into local namespace
double fetch; //Error!
cin >> fetch; //读取一个值到Jill::fetch
cin >> ::fetch; //读取一个值到全局变量fetch
...
}
::fetch 全局名称空间中的变量
4.指导原则
- 使用已命名的名称空间中声明的变量,而不是使用外部全局变量/静态全局变量;
- 若开发了一个函数库或类库,将其放在一个名称空间中;
- 仅将编译指令using作为一种将旧代码转换为使用名称空间的权宜之计;
- 不在头文件中使用using编译指令,若非要使用,应将其放在所有预处理器编译指令
#include
之后; - 导入时,首选using声明;
- 对于using声明,首选将其作用于设置为局部而不是全局;