C++ Primer Plus 学习之内存模型和名称空间

加油鸭


头文件

  • 如果文件名包含在尖括号中,则C++编译器将在存储标准头文件的主机系统的文件系统的中查找。如果文件名包含在双引号中,则编译器将在当前目录下查找。
  • 使用条件编译防止多次包含头文件。
    1
    2
    3
    4
    #ifndef XXX_H_
    #define XXX_H_
    ...
    #endif

存储持续性,作用域和链接性

C++存储方式是通过存储连续性、作用域和链接性来描述的

存储描述 持续性 作用域 链接性 如何声明 存储位置
自动 自动 代码块 在代码块中 栈中
寄存器 自动 代码块 在代码块中,使用关键字register 寄存器中
静态,无链接性 静态 代码块 在代码块中,使用关键字static 内存块
静态,外部链接性 静态 所有文件 外部 不在任何函数中 内存块
静态,内部链接性 静态 本文件 内部 不在任何函数内,使用关键字static 内存块
  • 如果定义一个静态外部链接性的变量,其他文件在使用时,需要引用声明使用关键字extern,且不进行初始化。

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

  • 链接性如果为外部,则名称可在文件间共享。
  • 链接性如果为内部,则名称只能由一个文件中的函数共享。
  • 自动变量的名称没有链接性,因为他们不能共享。

作用域解析运算符::

作用::就是当局部变量和全局变量名字重叠的时候,指定某变量一定是来自全局变量。

1
2
3
4
5
6
7
int a=5;
int main()
{
int a=3;
cout<<a<<endl;
cout<<::a<<endl;//作用域解析运算符,此时的a为全局变量的a
}


说明符

  • register 用于在声明中指示寄存器存储,而在C++11中,它只是显式地指出变量是自动的。
  • static 表示内部链接性。
  • extern 表面是引用声明,即声明引用在其他文件定义的变量。
  • thread_local(C++11新增) 指出变量的持续性与其所属的线程的持续性相同。thread_local变量之于线程,犹如常规静态变量之于整个程序。
  • mutable 用来指出,即使结构(或类)变量为const,其某个成员也可以被修改。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    struct student
    {
    char name[30];
    mutable int score;
    };
    int main()
    {
    const student a={"guo shen",100};
    a.score++;
    cout<<a.name<<' '<<a.score<<endl;
    }

cv-限定符之volatile

  • 即使程序代码没有对内存单元进行修改,其值也可能发生变化(可能受硬件影响)。
  • 如果不使用volatile变量,在再次访问之前编译器可能会认为值没有变化,从而进行优化(如将值放在寄存器中缓存起来)。
  • 使用volatile变量相当于告诉编译器,不要进行这种优化。

cv-限定符之const(不能修改的内存)

  • const 对全局变量的链接性有影响 – const全局变量的链接性为内部的。
  • 也是const变量能写在头文件而没有多重定义的原因。
  • 若想使用链接性为外部的const变量,则可以再在前面加extern进行定义,但其他文件使用此变量必须也要用extern关键字进行声明。
    1
    extern const int maxn = 100;

函数的链接性

  • 函数默认为外部静态的 即默认是extern的。
  • 可使用 static 关键字将其链接性设置为内部的。
    • 必须同时在原型和定义中使用static。
    • 内部静态函数将覆盖外部函数。

名称空间

名称空间特性

  • 为解决名称冲突的问题使用名称空间工具。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    namespace Tom{
    double pail;
    void fetch();
    int pal;
    struct Well {..};
    }
    namespace Jerry{
    char other;
    void fetch();
    int pal;
    struct Hill {..};
    }
  • 名称空间可以是全局的,也可以位于另一个名称空间中,但不可以位于代码块中。

  • 默认情况下,名称空间中声明的名称的链接性为外部的。
  • 访问某一名称空间中的名称要使用作用域解析符::
    1
    2
    3
    namespace Tom{
    char *name;
    }

using 编译指令和 using 声明

  • using 声明使特定的标识符可用 :using Tom::pal=1;
  • usng编译指令使整个名称空间所有的名称都可用。
  • 使用using 声明和using编译指令可能会增加名称冲突的可能性,使用作用域解析运算符就不会存在二义性。
  • 如果某个名称已经在函数声明了,则不能用using声明导入相同的名称。
  • 如果使用using编译指令,名称空间相当于全局的,那么局部名称将隐藏名称空间名,就像隐藏同名的全局变量一样。不过仍可以使用作用域解析运算符。

关键字new 和 delete

牛逼网友

1
2
3
4
// 初始值
int *p = new int (5);
// 分配对象数量
int *p = new int [10];