[Cpp基础] [03] 变量声明-定义及初始化

Last Updated on 2022年9月27日

变量的"声明,定义"以及"初始化"

想要彻底理解这一部分的内容,你应该对OS/进程/虚拟内存/编译/链接过程有一定的了解,仅从语言层次学习是比较抽象的.

声明和定义

  • 从编译的角度看:
    • 仅声明某个变量,那么就只创建了Symbol,这个Symbol对应的存储空间需要在后续的链接过程中resolve.
    • 定义某个变量,在创建Symbol的同时,编译器为其分配了存储空间, 这个存储空间可以被链接器reslove道引用这个Symbol的地方.
  • 对开发者而言:
    • 如果你希望使用某个已经存在的对象,那么就应该使用声明语句.
    • 每个定义语句都有"声明"的效果,不存在只定义不声明的语句.
  • 就C++而言,若语句仅有extern,且不含任何初始化部分,则该语句就是一个纯粹的声明,例如
    • extern T &val;//纯声明
    • extern T val;//纯声明
    • extern T val(ob);//定义
    • extern T val=ob;//定义

初始化,赋值和析构

  • 这三个概念很容易通过在特定位置插入函数调用来理解.
    • 初始化:对应了构造函数的调用.
    • 赋值:对应了赋值运算符的调用
    • 析构:对应了析构函数的调用.
  • 逻辑上说,所有的对象初始化操作都是在运行期,对应的构造函数将会被调用.
    • 这将用于解释全局变量/static变量构造函数的调用时机.
    • 内置类型的构造函数会有依场景由不同的行为:
    • 静态区的数据0初始化
    • 运行期的所有数据都随机初始化,如栈,堆,malloc,new等都是如此.
    • switch-case,goto都可以用于跳过构造函数的调用,部分编译器会对这种行为报错,因为这可能导致对象处于错误的状态
  • new/delete表达式都是复合操作,前者是malloc()+T()后者是~T()+free()
    • 对C++而言,placement new可以在特定地址手动的触发构造,这样创建的对象应当手动调用析构函数进行销毁,而不是使用delete
    • 对于内置类型,直接newmalloc的效果相同,获得的都是未初始化的内存,但是new可以添加初始化参数,如new int(10) ;new int[10]{1}

补充:栈/堆/静态区的对象

名称 功能 生命周期
栈区(0xFFFF方向) 存储函数调用栈帧,函数局部变量也存储在栈帧中 函数执行期间
堆区 由进程在运行期手动申请存储空间,并在其中创建对象 手动管理
静态区 编译系统在编译期预分配好的空间,主要供全局变量,static变量使用 整个进程
常量区(0x0000方向) 存储运行时不会改变的量,如程序代码,字符串等 整个进程