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


1.有关头文件

  1. 头文件中不要添加变量和函数定义。(多次引用会重复,内联函数除外)
    • 可包含在头文件中的内容有:函数/结构/类/模板的声明,使用#defineconst()定义的符号常量。
  2. #include<>只查找系统库,#include””先查找工作目录,没有再找系统库
  3. C++防止多重声明的防护方案:
    这样一来,即使包含了多次头文件,也只会忽略除了第一次之外的所有内容
    //testProtect.h
    #ifndef TESTPROTECT_H
    #define TESTPROTECT_H
    //头文件部分...
    //...
    //...
    #endif

2.存储持续性、作用域、链接性

 

 

  1. 微笑函数的作用域不能是局部的,因为函数不能在代码块内部定义。但链接性可以设置为内部的,具体见#12

  2. 静态、自动、动态变量的涵义都是相对于存储的持续性来讲的。
    静态变量不会在程序运行期间自动销毁。
    如下所示:
    int x = 0;//静态变量,链接性为外部
    static int y = 0;//静态变量,链接性为内部
    
    
    int main()
    {
        ...
    }
    
    void functin1()
    {
        static int z = 290;//静态变量,无链接性,只在本函数中可用,程序开始就存在。
    }
    注:静态变量只能使用常量表达式来初始化。。。未被初始化的所有位都被设置为0.。。

  3. 局部代码块中的变量会暂时隐藏全局代码块中的同名变量。
    此时要引用外部变量时可以在前面添加作用域解析操作符(::)。 ::sheepCount。
  4. auto声明一个自动持续性变量,默认声明时就是。
    auto float a = 5.6;


  5. C++通过使用堆栈来实现自动变量:程序预先留出一块内存视为堆栈来存储自动变量,开始一个指针指向栈底,一个指针指向栈顶,新增自动变量时加入栈顶,指针后移。自动变量结束时,栈顶重新指向开始时的位置。
  6. 寄存器变量:也是一种自动局部没有链接性的变量,但是存储在CPU寄存器中,访问速度比较快。
    register int int_fast; //注:该变量没有内存地址。只有当被频繁使用时声明


  7. 多文件程序中,只能在一个文件中定义一个外部变量,即使没有外部引用,也不能多次定义外部变量。
  8.  mutable存储说明符: 即使结构或类变量是const类型,其某个成员也可以被修改:
    struct data
    {
        char name[30]];
        mutable int accesses;//即使声明了const类型的该值也可以被修改。。。
    };
    const data veep = {"kkks", 0};
    veep.accesses = 19;
  9. volatile 关键字:(cv限定符的一种。const, volatile)。不让程序将变量放入寄存器。(默认情况下编译器会将多次引用的值放入寄存器,下次直接使用而不需要去查找该值)
    例如,把某个指针指向硬件位置,下次使用时再去查找该地址,有可能值已经被其它程序改变了。

  10. extern 关键字:引用声明。
    如果在文件的外部代码块中声明了全局(作用域)外部(链接性)变量 int sheepCount = 3;  
    要在另外一个文件B中使用它,需要在B中添加 引用声明
    extern double sheepCount;//注意,这里不能进行初始化,只有为变量分配内存空间时才能进行初始化。
    
    
  11. const 关键字:const关键字会使默认存储类型的链接性变成内部的(就像static一样)。这就是为什么可以放在头文件中了。如果多个文件都引用该头文件,每个文件中的const类型的常量都是内部链接性的,所以就不会出错。
    const int conValue = 88;//链接性为内部的。

    此时,如果要使const常量的链接性变为外部,可以通过extern关键字来来覆盖默认的内部链接性。与常规的 extern变量不同的是,此时的extern const变量必须被初始化,另外一个不同点是:在所有使用它的文件中都必须使用extern(包括定义的文件中)。
    extern const int states = 50; //链接性为外部的常量
  12. static 关键字:声明静态变量。会使外部链接性的变量的链接性变成内部的。在程序运行期间一直存在。
    即使static变量在代码块内部,也会将变量的存储持续性声明为静态的。在程序启动时初始化一次,以后再调用时不会重新初始化,值保留上次的值。
    static int internal_value; //会使外部链接性的变量的链接性变成内部的

    static关键字还可以将函数的链接性设置为内部的,只能在一个文件中使用。

  13. 单定义规则:多文件程序中,只能有一个文件包含某函数的定义,并且使用非内联函数的每个文件都要包含其函数原型。

    但内联函数不受该规则约束,可以在多个文件中包含定义,不过C++要求同一个函数的所有内联定义都必须相同。

  14. 语言链接性:不同编译器对同一函数生成的修饰名称不同,因此在链接编译模块时,要确保所有文件都是有同一编译器生成的。
    比如下面使用函数原型来指出要使用的约定:
    extern "C" void spiff (int); //将使用C语言的名称修饰格式来查找要函数
    extern void spoff (int);
    extern "C++" void spaff (int); //以上两个均采用C++格式的语言修饰来查找函数

  15. 一些小概念:
    编译器使用3块独立的内存:一块用于存放静态变量, 一块用于自动变量, 另一块用于动态存储。
    动态内存不受作用域和链接性规则控制,不适用于存储方案。但用来跟踪动态内存的指针适用于存储方案。
    如果要让一个跟踪动态内存的指针可以在多个文件中使用,可以把它定义成静态外部链接性的:
    float * p_fees;
    在其它文件中引用时只要加extern查找就行了:
    extern float* p_fees;
    于此同时要注意的是,在该静态指针定义时,不能直接用 new 进行初始化,因为只能用常量表达式来初始化静态变量(#2)。所以要在函数内部进行赋值:
    float * p_fees;
    //float * p_fees = new float[20];//不可取,非常量,不能用来初始化静态变量。
    
    void main()
    {
        p_fees = new float[20];//正确
    }


3.布局new操作符

  1. 布局 new 操作符与普通 new 操作符不同,它可以在指定位置分配空间。
    使用布局 new 操作符需要包含 new 头文件。
    #include <new>
    
    struct student
    {
    ...
    }
    
    int main()
    {
        char buf1[50];
        char * p2 = new (buf1) student;//在buf1中分配一个结构
        char * p3 = new (buf1) int[20];//在buf1中分配一个数组
    }

  2. 使用 布局 new 操作符分配的空间不能使用 delete 或 delete[] 来删除。

4.名称空间

  1. 几个概念:
    声明区域:变量声明所在的区域;如函数外的全局静态变量,声明区域为整个文件。
    潜在作用域:从声明开始到声明区域结束的位置。
    作用域:变量可见的范围。
  2. 根据是否带名称空间装饰,变量又分为 未限定的名称(pail) 和 限定的名称(Jack::pail)。

  3. using 声明:using Jack::pail; 这将变量添加到了局部声明区域中,因此不能再声明另一个同名的变量。
    using 编译指令:using namespace Jack; 使名称空间中的所有都可用,此时可以声明与名称空间中名称同名的局部变量,这样局部版本变量会暂时隐藏名称空间版本的全局变量。
    在选择使用 using声明 和 using编译指令 时,应尽量选择使用 using 声明。
    且在使用using声明时,首选将其作用域设置为局部的。


  4. 嵌套的名称空间的特性:
    namespace Jill
    {
        int pail;
        namespace element
        {
            namespace fire
            {
                int countSheep;
                ...
            }
            ...
        }
        ...
    }
    
    
    //另一名称空间中
    namespace myth
    {
        using namespace Jill::pail;//此时使用using声明引入pail局部变量
    
        cin >> Jill::pail;
        cin >> myth:pail;//可以同时用这两种方法来调用pail,因为它同时在这两个名称空间中
    }


    同时还可以给名称空间创建别名:
    namespace AliasN = myth::elements::fire;
    
    using fire::countSheep;


  5. C++不赞成在名称空间 或 全局作用域中使用关键字 static ,替代的方法是使用 未名称的名称空间:未命名的名称空间中的变量只有在当前文件中是可见的。
    namespace myth
    {
        static int counts;//静态变量,链接性为内部。。不赞成使用的(不管是否在名称空间中)
        namespace
        {
            int counts2;//静态变量,链接性为内部。。。赞成这样使用
            ...
        }
    }


  6. :老式的头文件(如iostream.h)没有使用名称空间,但新式的头文件(iostream)使用的std名称空间。

 

 

注:

posted @ 2013-08-29 10:34  toffrey  阅读(260)  评论(0)    收藏  举报