C++证道之路第九章内存模型和名称空间

一、单独编译

请不要将函数定义或变量声明放到头文件中,这样做对于简单的情况可能是可行的,但通常会引来麻烦。

头文件管理

在同一个文件中,只能将同一个头文件包含一次。记住这个规则很容易,但很可能在不知情的情况下将头文件包含多次。例如,可能使用包含了另外一个头文件的头文件。

下面的代码片段意味着仅当以前没有使用预处理器编译指令#define定义命长COORDIN_H_时,才处理#ifndef和#endif之间的语句:
 

#infnedf COORDIN_H_

...

#endif

二、储存持续性、作用域、和链接性。

自动储存持续性:在函数定义中声明的变量(包括函数参数)的储存持续性为自动的。它们在程序开始执行其所属的函数或代码块时被创建,在执行完函数或代码块时,它们使用的内存被释放。

C++有两种储存持续性为自动的变量。

静态储存持续性:

在函数定义外定义的变量和使用关键字static定义的变量的储存持续性都为静态。它们在程序的整个运行过程中都存在。

线程储存持续性:

当前,多核处理器很常见,这些CPU可以同时处理多个执行任务。这让程序能够将计算放在可并行处理的不同线程中。如果变量是使用关键字thread_local声明的,则其声明周期与所属的线程一样长。

动态储存持续性:

用new运算符分配的内存将一直存在,直到使用delete运算符将其释放或程序结束为止。这种内存的储存持续性为动态,有时被称为自由储存或堆。

作用域和链接

作用域描述了名称在文件(翻译单元)的多大范围可见。

链接性描述了名称如何在不同单元间共享。

自动变量和栈:

由于自动变量的数目随函数的开始和节数而增减,因此程序必须在运行时对自动便令进行管理。常用的方法是留出一段内存,并将其视为栈,以管理变量的增减。之所以被称为栈,是由于新数据被象征性的放在原有数据的上面。(也就是说,在相邻的内存单元中,而不是在同一个内存单元中),当程序使用完后,将其从栈中删除。栈的默认长度取决于实现,但编译器通常提供改变栈长度的现象。程序使用连个该指针来跟踪栈,一个指针指向栈底,也就是栈开始的位置,另一个指针指向栈顶,下一个可用内存单元。

栈是(LIFO)先进后出的。

静态持续变量

C++为静态储存持续性变量提供了3中链接性:外部链接性(可在其他文件中访问)、内部链接性(只能在当前文件中访问)和无链接性(只能在当前函数或代码块中访问)。

要想创建链接性为外部的静态持续变量,必须在代码块的外面声明它;

要创建链接性为内部的静态持续变量,必须在代码块的外面声明它,并使用static限定符;

要创建没有链接性的静态持续变量,必须在代码块的内部声明它,并使用static限定符。

引用声明使用关键字extern,且不进行初始化;否则,声明为定义,导致分配储存空间。

全局变量和局部变量

既然可以选择使用全局变量或局部变量,那么到底应该使用哪种呢?首先,全局变量非常具有吸引力——因为说有的函数能访问全局变量,因此不用传递参数。但易于访问的代价很大——程序不可靠。

静态持续性,内部链接性

将static限定符用于作用域为真个文件的变量时,该变量的链接性将为内部的。

注意:

在多文件程序中,可以在一个文件(且只能在一个文件)中第一一个外部变量。使用该变量的其他文件必须使用关键字extern声明它。

可使用外部变量在多文件程序的不同部分之间共享数据;可使用链接性为内部的静态变量在同一个文件中的多个函数之间共享数据(名称空间提供了另外一种共享数据的方法)。另外,如果将作用域为整个文件的变量变为静态的,就不必担心其名称空间与其他文件中的作用域为整个文件的变量发生冲突。

静态储存持续性、无链接性

无链接性的局部变量。

将static限定符用在代码块中定义的变量。在代码块中使用static时,将导致局部变量的储存持续性为静态的。这意味着虽然该变量只在该代码块中可用,但它在该代码块不处于活动状态时仍然存在。因此在两次函数调用之间,静态局部变量的值将保持不变。

函数和链接性

和变量一样,函数也有链接性,虽然可选择的范围比变量小。和C语言一样,C++不允许子啊一个函数中定义另外一个函数,因此所有函数的储存持续性都自动为静态的,即在整个程序执行期间都一直存在。在默认情况下,函数的链接性为外部的,即可以在文件间共享,实际上,可以在函数原型中使用关键字extern来指出函数是在另一个文件中定义的,不过这是可选的。

另一种形式的链接性——语言链接性,也对函数有影响。

注意:在程序结束时,有new分配的内存通常都将被释放,不过情况也并不总是这样。例如,在不那么健壮的操作系统中,在某些情况下,请求大型内存块将导致该代码块在程序结束不会被自动释放。最佳的做法是,使用delete来释放new分配到的内存。

定位new运算符

通常,new负责在堆中找到一个足以能够满足要求的内存块。new运算符还有另一种变体,被称为定位new运算符

名称空间

在C++中,名称可以是变量、函数、结构、枚举、类以及类和结构的成员。当随着项目的增大,名称相互冲突的可能性也将增加。使用多个厂商的类库时,可能导致名称冲突。

传统的C++名称空间

声明区域、潜在作用域。

C++关于全局变量和局部变量的规则定义了一种名称空间层次。每个声明区域都可以声明名称。这些名称独立于在其他声明区域中声明的名称。在一个函数中声明的局部变量不会与在另一个函数中神功的局部变量发生冲突。

新的名称空间特性

C++新增了这样一种功能,即通过定义一新的声明区域来创建命名的名称空间,这样做的目的之一是提供一个声明名称的区域。一个名称空间中的名称不会与另外一个名称空间的相同名称发生冲突,同时允许程序的其他部分使用该名称空间中声明的东西。

using声明和using编译指令

C++提供了两种机制,using声明和using编译指令,一次来简化对名称空间中名称的使用。using声明使特定的标识符可用,using编译指令使整个名称空间可用。

时候用using编译指令导入一个名称空间中所有的名称与石红多个using声明是不一样的,而更像是大量使用作用域解析运算符。使用using声明时,就好像声明了相应的名称一样。如果某个名称已经在函数中声明了,则不能用using声明导入相同的名称。然而,时候用using编译指令时,将进行名称解析,就像在包含了using声明和名称空间本身的最小声明区域中声明了名称一样。

注意:假设名称空间和生命区域定义了相同的名称。如果试图使用using声明将名称空间的名称导入该声明区域,则这两个名称会发生冲突,从而出错。如果使用using编译 指令将该名称空间的名称导入该声明区域,则局部版本将隐藏名称空间版本。

名称空间及其前途

下面是一些指导性的原则

使用在已命名的名称空间中声明的变量,而不是使用外部全局变量。

使用在已命名的名称空间中声明的变量,而不是使用静态全局变量。

如果开发了一个函数库或类库,将其放在一个名称空间中。事实上,C++当前提倡将标准函数库放在名称空间std中,这种做法扩展到了来自C语言中的函数。

仅将编译指令using作为一种将旧代码转换为使用名称空间的权宜之计。

不要在头文件中使用using编译指令,首先这样做掩盖了要让哪些名称可用;另外 ,包含头文件的顺序可能影响程序的行为。如果非要使用编译指令using,应将其放在所有预处理器编译指令#include之后。

导入名称时,首先石红作用域解析运算符或using声明的方法。

对于using的生命,首选将其作用域设置为局部而不是全局。

  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值