C++ Primer Plus: 第九章 内存模式和名称空间

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/budding0828/article/details/82597959

C++ Primer Plus: 第九章 内存模式和名称空间

9.1 单独编译

  • C++鼓励程序员将组建函数放在独立的文件中。可以单独编译这些文件,然后将他们链接成可执行的程序。
  • 不要将函数定义或变量声明放到头文件中。因为如果在头文件中包含一个函数定义,然后在其他两个文件中包含该头文件,则同一个程序中将包含同一个函数的两个定义。除非函数是内联的,否则这将出错。
  • 头文件常包含的内容
    1. 函数原型
    2. 使用#define或const定义的符号常量
    3. 结构声明
    4. 类声明
    5. 模板声明
    6. 内联函数
  • 使用预处理编译器指令#ifndef可以避免多次包含同一个文件。
  • C++标准允许每个编译器设计人员以他认为合适的方式实现名称修饰,也就是说,两个编译器将为同一个函数生成不同的修饰名称。名称的不同将使链接器无法接一个编译器生成的函数调用与另一个编译器生成的函数定义匹配。通常可以使用自己的编译器重新编译源代码来消除链接错误。

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

  • C++使用四种不同的方案来存储数据:

    1. 自动存储持续性:在函数定义中声明的变量,函数参数的存储持续性为自动的。在执行完函数或代码块时,它们使用的内存被释放。
    2. 静态存储持续性:在函数定义外定义的变量和使用的关键字static定义的变量的持续性都为静态。它们在程序整个运行过程中都存在。
    3. 动态存储持续性:用new运算符分配的内存将一直存在,直到使用delete运算符将其释放或程序结束为止。
    4. 线程存储持续性(C++11):其生命周期与所属的线程一样长。
  • 作用域和链接:

    • 链接性描述了名称如何在不同单元间共享。链接性为外部的名称可以在文件间共享,链接性为内部的名称只能由一个文件中的函数共享。
自动存储持续性
  • 程序对自动变量的管理:留出一段内存,并将其视为栈,以管理变量的增减。
  • 栈的默认长度取决于实现,但编译器通常提供改变栈长度的选项。程序使用两个指针来跟踪栈,一个指针指向栈低——栈的开始位置,另一个指针指向栈顶——一下个可用内存单元。当函数被调用时,其自动变量将被加入到栈中。函数结束时,栈顶指针被重置为函数被调用前的值,从而释放新变量使用的内存。
  • 寄存器变量:register int count; 关键字register最初是由C语言引入,它建议编译器使用CPU寄存器来存储自动变量,目的是提高访问变量的速度。只是随着硬件和编译器变得越来越复杂,这种提示表明变量用得很多,编译器可对其做特殊处理。在C++11中,这种提示作用也失去了。
静态持续变量
  • 包括三种类型:外部链接性(可在其他文件中访问),内部链接性(只能在当前文件中访问),无链接性(只能在当前函数或代码块中访问)。
  • 程序不需要使用特殊的栈来管理他们。编译器将分配固定的内存块来存储所有的静态变量,这些变量在整个程序执行期间一直存在。
  • 如果没有显示地初始化静态变量,编译器将把它设置为0,在默认情况下,静态数组和结构将每个元素或成员的所有位都设置为0.
int global = 100;   //外部链接性
static int one_file = 10;   //内部链接性
int main()
{

}
void func()
{
    static int count = 1;   //无链接性
}
  • func()没有执行时,count也在内存中。
  • 在多个文件中使用外部变量,只需在一个文件中包含该变量的定义,但在使用该变量的其他所有文件中,都必须使用关键字extern声明它。
//file1
int cats = 20;
//file2
extern int cats;
  • cv限定符:cv表示const和volatile。

    • volatile:关键字表明:即使程序代码没有对内存单元进行修改,其值也可能发生变化。该关键字的作用是为了改善编译器的优化能力。例如,假设编译器发现,程序在几条语句中两次使用了某个变量的值,则编译器可能不是让程序查找这个值两次,而是将这个值缓存到寄存器中。这种优化假设变量的值在这两次使用之间不会变化。如果不将变量声明为volatile,则编译器将进行这种优化;将变量声明为volatile,相当于告诉编译器,不要进行这种优化。
  • mutable:可以用来之处,即使结构或类变量为const,其某个成员也可以被修改。

struct data
{
    char name[30];
    mutable int access;
};
const data veep ={"abd", 0};
veep.access++;
  • 函数和链接性:

    1. C/C++不允许在一个函数中定义另外一个函数,因此所有函数的存储持续性都是自动为静态的,即在整个程序执行期间都一直存在。在默认情况下,函数的链接性为外部的,即可以在文件间共享。
    2. 可以使用关键字static将函数的链接性设置为内部的,使之只能在一个文件中使用。
  • C++寻找函数的方式

    1. 如果该文件中函数的原型指出该函数是静态的,则编译器只在该文件中查找函数定义。
    2. 否则,编译器将在所有的程序中查找。
    3. 如果没有找到,则编译器在库中搜索。
动态存储变量
  • 通常,编译器使用三块独立的内存:一块用于静态变量,一块用于自动变量,另一块用于动态存储。
  • 使用new初始化:使用括号 int* pi = new int (6);
  • 定位new运算符:能够指定要使用的位置。程序员可能使用这种特性来设置其内存管理规程、处理需要通过特定地址进行访问的硬件或在特定位置创建对象。
struct chaff
{
    char dross[20];
    int slag;
};
char buffer1[500];
chaff *p1, *p2;
p1 = new (buffer1) chaff;
p2 = new (buffer1+sizeof(chaff)) chaff;

9.3 名称空间

  • 示例
namespace Jack{
    double pail;
    void fetch();
    int pal;
}
  • 名称空间可以是全局的,也可以是位于另一个名称空间中,但不能位于代码块中。因此,在默认情况下,在名称空间中声明的名称的链接性为外部的。
  • 除了用户定义的名称空间外,还存在另一个名称空间——全局名称空间。它对应于文件级声明区域,因此前面所说的全局变量现在被描述为位于全局名称空间中。
  • 名称空间是开发的,可以把名称加入到已有的名称空间中。
namespace Jack{
    int count;
}
//Jack已经在前面被声明了
  • 访问:使用作用域解析运算:: Jack::pail = 2.0;
  • 使用命名空间:using声明
int main()
{
    using Jack::count;  //某一名称可用
    count = 1;
}
//或者
using namespace Jack;   //所有名称可用
int main()
{
    pail = 9.9;
}
  • 局部名称将隐藏名称空间名。
  • 名称空间可嵌套:
namespace Jack{
    int a;
    namespace Mike{
        int b;
    }
}

猜你喜欢

转载自blog.csdn.net/budding0828/article/details/82597959