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];