• 《C++ Primer Plus》《9、内存模型和名称空间》


    前言

    通常情况下,大型程序都是由多个源代码文件组成,这些文件可能共享一些数据,这涉及到如何编译的问题,本章对代码的编译做重点的介绍。

    1 单独编译

    在有多个源文件时,先对这些文件进行编译,然后将它们链接成可执行的程序。单独编译是出于开发的效率,可移植性提出来的。首先了解一下背景,在大型项目下有多个源文件,若是每个程序都包含某个函数的定义,首先程序会显得冗余,修改起来比较麻烦;其次,要是进行修改,所有文件都需要重新编译一次。将一个程序放在多个文件中会有很多新的问题出现。因此C++开发人员提出了#include 来解决这个个问题,与其将结构声明加入到每一个文件中,不如将其放到头文件,要修改声明时,只需要在头文件修改即可。
    因此可以将项目的文件大体分为3类:
    1)头文件:包含结构声明和这些结构函数的原型;
    2)源代码文件:包含与结构有关的函数的代码;
    3)源代码文件:包含调用与结构相关的函数的代码;
    对于头文件做一些额外的说明:
    在大型项目中,可能会重复包含一个头文件,这样会使得“重复定义“的现象发生,为了提前预防这种状况,需要添加头文件保护,示例如下:

    #ifndef _HEADER__
    #define _HEADER__
    ……(statement)
    #endif
    
    • 1
    • 2
    • 3
    • 4

    这样就可以确保头文件在编译的过程中不会重复包含。
    头文件包含内容如下:
    1)函数原型;
    2)使用#define或const定义的符号常量
    3)结构声明;
    4)类声明;
    5)模板声明;
    6)内联函数
    头文件做的活,基本上都是声明,提前告诉预编译器的变量大小,让编译器“做好准备”。书中给出了示例:coording.h,file1.cpp,file2.cpp。在头文件种声明了结构体,函数原型;
    在file2.cpp中对coording.h声明的函数做出具体的实现,而file1.cpp一般是主函数,并会用到之前声明函数的调用。
    下图展示了多个函数编译最终合成一个可执行程序的过程。
    在这里插入图片描述

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

    1)自动存储连续性:
    一般指的是在函数体内部定义的变量,在执行完函数或者代码块时,他们使用的内存便会被释放。
    2)静态存储持续性
    在函数定义外定义的变量和使用关键词static定义的变量的存储持续性都为静态,在程序的整个运行过程都存在。
    3)线程存储持续性
    CPU可同时处理多个执行任务,让程序能够将计算放在可并行处理的不同线程中。
    4)动态存储持续性
    用new运算符分配的内存将一直存在,直到使用delete运算符将其释放或程序结束为止。

    2.1作用域和链接

    作用域描述了·名称在文件多大范围内可见。例如局部变量与全局变量。局部变量只能在函数中局部起作用,而全局变量在整个文件中都可以被使用。C++函数的作用域可以是整个类或者某个名称空间,但绝对不是局部的。
    链接性描述了名称空间如何在不同单元间共享,链接性为外部的名称空间可以在文件间共享,链接性为内部的名称只能由一个文件中的函数共享。

    2.2自动存储连续性

    默认情况下,在函数中声明的函数参数和变量的存储持续性为自动,作用域为局部,没有链接性。
    
    • 1

    在这里插入图片描述

    2.3静态持续变量

    C++的静态存储变量提供了三种链接性:外部链接性(可在其他文件夹中访问),内部链接性(只能在当前文件夹中访问),无链接性(只能在当前函数或代码块中访问);不管链接性如何,这些变量在整个程序执行期间都是一直存在的。
    在这里插入图片描述

    静态变量的初始化有零初始化,表达式初始化与动态初始化。

    2.4静态持续性、外部链接性

    链接性为外部的变量通常简称为外部变量,他们的存储持续性为静态,作用域为整个文件。书中给出了示例,在一个文件中定义了一个变量,另一个文件想要使用他时只需要extern这个变量即可。

    2.5静态持续性、内部链接性

    将static限定符用于作用域为整个文件的变量,该变量的链接性是内部的。在多个文件中,这样的声明就很有意义,例如:链接为内部的变量只能在其所属的文件中使用;但常规外部变量具有外部链接性,即可以在其他文件中使用。
    书中给出了twofile1.cpp,twofile2.cpp,通过给出不同变量的地址,观察变量是否还保持一致。

    2.6静态存储连续性、无链接性

    这种变量是这样创建的,将static限定符用于在代码块中定义的变量;在代码块中使用static,将使得局部变量的存储持续性转化为静态的。如果初始化了局部静态变量,则程序只在启动的时刻进行一次初始化,书中给出了示例代码。

    2.7说明符和限定符

    C++关键字提供了有关存储的信息,包括cv限定符,mutable,const,前两个与硬件相关,着重讲一下const限定符。默认情况下,全局变量的链接性为外部的,但是const全局变量的链接性为内部的,在变量前加上了const关键字,就像使用了static说明符一样。

    2.8函数和链接性

    函数也具备链接性,所有函数的存储持续性默认为静态的,所以函数在程序执行期间都一直存在。默认情况下,函数的链接性为外部的,即可以在文件间共享;但是若是在函数前加上static,将函数的链接性设置为内部的,使之只能在一个文件中使用。

    2.9语言链接性(了解)

    链接程序要求每个不同的函数都有不同的符号名。在C++中,同一个名称可能对应多个函数,必须将这些函数翻译为不同的符号名称。

    2.10存储方案和动态分配

    通常编译器使用三块独立的内存:静态变量,自动变量,动态存储。在C++中由new分配的内存称为动态内存,由new分配的内存将一直保留在内存中,直到使用delete运算符将其释放掉。
    1)使用new运算符初始化
    a.为内置的标量类型分配存储空间并初始化

    例子:int *pi = new int(6)  //一个指向6的整型数值的一个指针*pi
    
    • 1

    b.初始化结构体

    例子:struct where{double x,double y,double z};
    where* one = new where{1.0,2.0,3.0}; //声明一个one的指针指向这个结构体
    
    • 1
    • 2

    2)new失败时
    以前new找不到请求的内存量返回一个空指针,现在会引发异常std::bad_alloc。
    3)new:运算符,函数和替换函数
    分配函数与释放函数
    new和new[]对应的delete和delete[],书中给出了示例。
    4)定位new运算符
    new负责在堆中找到一个足以能够满足要求的内存块。new还有一种变体,称为定位new运算符,它让您能够指定要使用的位置。书中给出了示例的代码。
    下面是对代码块的补充说明:

    pd1 = new double[N];             //use heap
    pd2 = new (buffer) doubkle [N];     //use buffer array
    
    • 1
    • 2

    起始地址:
    常规new将指针放在很远的位置,若是重新进行赋值,地址也会进行更改;而定位new运算符不一样,他每次赋值的地址都是从buffer的起始地址进行的。
    是否使用delete:
    常规new运算符要是想从最初的地址进行重新赋值,可以先delete[]一下,因为delete用来释放指向常规new运算符分配的堆内存;而定位new运算符,buffer指定的内存是静态内存,用delete无法进行删除。

    3 名称空间

    名称可以是变量,函数,结构,枚举,类以及类和结构的成员,随着项目的增大,名称内相互冲突的可能性也将增加,例如多个厂商都定义了list,但定义的方式不兼容,这种冲突被称为名称空间问题。C++为了解决这类问题提供了名称空间工具,以便更好地控制名称的作用域。

    3.1 传统的C++名称空间

    首先介绍一些术语,声明区域,作用域和潜在作用域。
    声明区域:可以在其中声明的区域;
    作用域:变量对程序而言可见的范围被称为作用域;
    潜在作用域:变量可能在这片区域被另一个嵌套声明区域中声明的同名变量隐藏;

    在这里插入图片描述

    3.2新的名称空间特性

    1)using声明和using编译指令
    using声明使得特定的标识符可用,using编译指令使得整个名称空间可用。
    2)using编译指令和using声明的比较
    出于安全性考虑,一般来说尽量使用using声明,因为他只导入指定的名称,如果他有局部变量发生冲突,编译器会发出指示;而直接使用using编译指令,遇到上述情况,局部变量会直接覆盖名称空间的版本,编译过程中而不发出指示,这样代码在执行过程中就可能会出现问题。
    3)名称空间的其它特性
    a.可以将名称空间的声明进行嵌套;
    b.可以在名称空间内进行using编译指令和using声明;
    4)可以通过省略名称空间的名称来创建未命名的名称空间,这种操作为链接性为内部的静态变量提供了一种替代。

    3.3名称空间示例

    书中给出了代码示例说明名称空间的一些特性。

    3.4名称空间及其前途

    书中给出了使用名称空间的指导原则。
    在这里插入图片描述
    使用名称空间的最终目的是简化大型项目的管理工作。

    4总结

    本章介绍了程序中变量,函数的存储型,链接性。讲述了动态分配内存的两种方法;讲述了名称空间的特性,以及如何使用名称空间。

    5 参考

    5.1 《C++ Primer Plus》

  • 相关阅读:
    力扣:92. 反转链表 II(Python3)
    网络协议之:redis protocol 详解
    Parallel 与 ConcurrentBag<T> 这对儿黄金搭档(C#)【并发编程系列_2】
    每天五分钟机器学习:使用支持向量机的时候,如何选择模型参数?
    免杀对抗-java语言-shellcode免杀-源码修改+打包exe
    Tableau可视化分析:深入理解数据结构及字段处理方法
    Hook原理--逆向开发
    交换机和路由器技术-19-HSRP和PVSTP综合实验
    Context与Reducer
    .Linux基础正则表达式字符
  • 原文地址:https://blog.csdn.net/zwh1298454060/article/details/136292414