chapter 2.pdf

初始化/赋值

image.png

  • 字面值:真实的数,1,5,10等
  • 初始化比赋值多的操作:
    • 开辟内存空间
      • int x=10 对应 mov DWORD PTR [rbp-4] , 10
    • 把标识符与内存空间对应起来
      • x = y 对应
        • mov eax, DWORD PTR //[rbp-8] 这里[rbp-8]和y对应,读出y放到寄存器中
        • mov DWORD PTR [rbp-4], eax
        • eax 寄存器

image.png

  • 值和对象都有类型
    • 字面值也有类型
  • 初始化/赋值可能涉及到类型转换
    • int x=10.5 //10.5是浮点数,在保存的时候只保存10
      • mov DWORD PTR [rbp-4],10

image.png

类型详述

类型是编译器的概念,可执行程序中不存在类型概念

  • 上图,汇编中没有int等类型
  • C++强类型语言,在编译的时候时刻和类型打交道,编译后就没有类型了
  • 类型:表示数值的含义及如何解析,更好的描述程序,防止误用
    • 内存大小(sizeof),
      • 不同编译环境大小可能不一致,
      • 64位机器,处理64位更容易,那么int对应的位数不一样
    • 取值空间(std::numrilc_limits获取取值空间,头文件limits),超过取值空间会溢出
      • image.pngimage.png
      • int, 4byte,32bit,取值个数第三章:对象与基本类型 - 图6
      • 超过取值空间会溢出,上溢出到最小值,下溢出到最大值

image.pngimage.png

  • 对齐信息
    • int x= 0, 开辟8000-8003字节保存x,而不是7999-8002
    • CPU从内存中读写过程中先经过cash。读写单位为cash line,cat coherency_line_size可以获取到cash line 大小
      • 如果x的对齐不好,存储在7999-8002,那么cpu要读取(8000-64)~ 7999,8000-8064两次读取,再拼接
      • alignof(int) 获取到int类型的对齐信息
      • 对齐信息对结构体大小产生影响

image.png

  • 描述可以执行的操作,加减乘除或者自定义的操作等
    • 类型可以划分为基本类型和复杂类型
  • 基本(内建)类型
    • 字符类型:char,wchar_t,char16_t,char32_t
      • char 一般用于表示ASCII编码,刚好256个字符/UTF8编码
      • wchar_t 宽字节类型
      • 用char32_t表示最全的字符集UNIcode
    • 整数类型:
      • 带符号整数:int,short ,long,long long,不同类型尺寸不一样,分别4,2,8,8,不同环境不一样,有些环境long long,与long尺寸不一样
      • 无符号整数:unsigned + 带符号整数类型
      • 浮点类型:float,double,long double
        • 可以表示小数
    • void
  • 复杂类型:由基本类型组合,变种所产生的类型,可能是标准库引入,或自定义类型

    字面值

  • 在程序中直接表示为一个具体数值或字符串的值
  • 每个字面值都有其类型
    • 整数字面值:20(十进制),024(八进制),0x14(十六进制)——int型
    • 浮点数:1.3,1e8 ——double型
    • 字符字面值:’c’,’\n’,’\x4d’ ——char型
    • 字符串字面值:”Hello” ——char[6]型,双引号,后面有’\0’,结束符
    • 布尔字面值:true,false ——bool型
    • 指针字面值:nullptr ——nullptr_t 型
  • 可以在字面值加前缀或者后缀改变类型
    • 1.3(double)—— 1.3f (float型)
    • 2(int型)—— 2ULL(unsigned long long 型)
  • 可以引入自定义后缀改变字面值类型,输入参数类型仅限如下图。应用:定义时间,kg,g等单位

image.pngimage.png
image.png

变量

  • 对应了一段存储空间,可以改变其中内容
  • 变量的类型在其首次声明(定义)时指定
    • int x:定义一个变量x,其类型为int
    • 变量声明与定义的区别:extern前缀,无前缀,全局变量定义,有前缀为声明
  • 变量的初始化与赋值
    • 初始化:在构造变量时赋予的初始值
      • 缺省初始化
        • 在函数内部,局部变量,未初始化的值为随机值。
          • 构造成本高,函数被调用次数可能很多
        • 在函数外部,全剧变量,未初始化的变量为0。
          • 构造成本低,只初始化一次
      • 直接/拷贝初始化
        • int x = 10;拷贝初始化
        • 直接初始化
          • int x(10); ()是调用了类型的构造函数初始化,对于内置类型来说,编译器有默认的构造函数
          • int x{10}; {}c++11支持,列表初始化。如果提供的值又无法用来列表初始化,则调用构造函数
        • 注意:extern的全局变量加上初始化后就从声明变为了定义,会出现重定义错误
      • 其他初始化
    • 赋值:修改变量所保存的数值

(隐式)类型转换

  • 为变量赋值时可能涉及到的转换:
    • bool与整数之间的转换:
    • 浮点数和整数之间的类型转换:
  • 隐式类型转换不只发生在赋值时
    • if判断:if(3),3转为bool值
    • 数值比较:(x<y),转为bool值,
      • 无符号数和带符号数做比较时,把带符号数转为无符号数,如下,输出0image.png
      • std::cmp_XXX(c++20)可以避免上述情况image.png
  • 提升转换:小内存类型转为大内存类型,无结果差异
  • 压缩转换:精度损失
  • unsigned int -> int 会发生数值变化,

复合类性:从指针到引用

指针:一种间接类型

image.png

  • 特点
    • 指向不同的对象
      • int x,y;
      • int* p = &x;
      • p = &y;
    • 具有相同的尺寸
      • 所有指针都是8个字节,不同类型的指针尺寸仍相同
      • 指针保存地址,64位机,内存最大为2^64,所以保存地址需要64bit,即8字节
  • 相关操作
    • &:取地址操作符,得到内存空间地址对应的值,
      • 通常将地址赋值给指针
      • 注意,需要有地址,变量有地址,字面值(右值)无地址
    • *:解引用操作符,
      • 访问指针保存的首地址,到对应首地址,读取数据
      • 指针类型决定读取连续多长内存中的数据
  • 指针缺省初始化
    • 在函数内局部的,是随机的
    • 在全局,值为0,地址0不能解引用,崩溃
    • 缺省初始化指向的内存不一定存在
    • int *p = NULL/0, 更安全,能报出错误
      • 拷贝初始化,存在类型转换,危险。函数重载,
        • void fun(int ) void fun(int), fun(0) fun(p),两者调用不同fun,对于int *p = 0,导致行为不同
        • nullptr不能隐式转换为0,fun(nullptr)调用fun(int *),不会导致行为不同,程序更稳定
    • 注意:指针初始化尽量为 int* p = nullptr;
  • 指针的定义
    • int* p = &val;
    • int* p = nullptr;
  • 关于nullptr
    • 一个特殊的对象,类型(nullptr_t),表示空指针
    • 类似于C中的NULL,但更加安全
  • 指针与bool的隐式转换:
    • 非空指针可以转换为true;
    • 空指针转为false
  • 指针的主要操作:
    • 解引用: *p
    • 增加: p = p+1, 指向的位置移动到地址下一个,实际地址移动一个int(类型)长度,4
    • 减少:p=p-1,指向的位置移动到地址上一个,实际地址移动一个int(类型)长度,4
    • 判等:判断两个指针是否相等
    • 比较大小,只在数组中用。在栈里分配,内存按先后顺序,在堆里分配,内存无先后顺序
  • void *指针
    • 没有记录对象的尺寸信息,可以保存任意地址
    • 支持判等操作,不支持加减
    • 可以转为任意类型指针,也可以由任意类型指针转为void*,但是丢掉了对象的尺寸信息(类型)
    • image.png
  • 指针的指针
    • int** pp = &p;
  • 指针VS对象,为间接引用。
    • 对于自定义的较大的对象,复制操作比较慢,指针减小传输
    • 对于不支持复制的对象(独占内存的对象),使用指针
    • 指针读写成本高,两次地址访问
    • 作为函数参数传入,可以修改指针所指地址内的值
    • image.png
  • 指针的问题
    • 可以为空
    • 地址信息可能非法
    • 解决方案:引用

      引用

常量类型和常量表达式

  • 常量表达式:const,只能读不能写
    • 编译期
      • 防止非法操作:写操作
      • 优化程序逻辑:int y = (const)x + 1; const是常量,在编译的时候直接给出y的值
  • 常量指针与顶层常量
    • 底层(指针的内容)常量:const int ptr/ const出现在的左边:表示指针指向 const int类型
    • 顶层(指针)常量:int const ptr: 指针对象不能修改,const出现在右边,表示指针类型为const
    • 常量指针可以指向变量
  • 常量引用
    • 可以绑定变量
    • 可读不可写
    • 主要用于函数形参:使用引用避免传参拷贝
      • 对于小的内部类型(int,bool)等,直接使用拷贝传参更合适,解引用费时且地址大小可能小于类型大小
    • 可以绑定字面值
    • 不可修改绑定对象
  • 常量表达式

    • 编译期常量:优化编译,
    • 使用constexpr声明,c++11
      • constexpr int y2 = 3
        • y2类型为const int
        • constexpr只为了让编译期识别为编译期常量
      • constexpr const int* ptr = nullptr;
        • ptr类型为 const int* const
        • constexpr修饰ptr为常量指针

          类型别名与类型的自动推导

          类型别名,

          引入特殊的含义或便于使用
  • (如:size_t)

    • 用于不同系统的代码移植
    • int32_t,int64_t,即使在不同系统上,也能够保证字节数不变,具体是哪种类型的别名和系统相关

      两种引入类型别名的方式

  • typedef int MyInt

    • 数组的类型别名:typedef char MyCharArr[4],不直观
  • using MyInt = int;(C++11)
    • using MyCharArr = char[4],更直观
  • 类型别名与指针,引用的关系

    • using IntPtr = int*
      • const IntPtr ptr = &x,此处const修饰指针,修饰整个类型别名,表示顶层常量
    • 不能使用类型别名构造引用的引用,以下两个相等
      • using RefInt = int&
      • using RefRefInt = RefInt&

        类型的自动推导

  • auto,需要有初始化表达式

  • 常见形式
    • auto:常用形式,但会类型退化
      • int x1 = 3; int& ref = x; auto ref2 = ref
        • 这里ref2类型退化为int,而非int&
    • auto& 可以避免退化
      • const int x=3; auto y=x;其中y退化为int,x作为右值,变为int
      • const int x=3; auto& y=x; 其中y为const int&
    • const auto/constexpr auto:推导出的是常量/常量表达式类型
    • decltype(exp):
      • 对于右值,返回exp表达式的类型,不会引入类型退化
        • decltype(3.5+15l) x = 3.5+15l;
      • 对左值表达式,表达式不只有名称,自动加引用
        • int x=3;int* ptr =&x
          • decltype(*ptr) int&
          • decltype(ptr) int*
          • decltype(x) int -> x 左值表达式,但只有名称
          • decltype((x)) int& -> (x) 左值表达式,且不止有一个名称
        • const int& y = x;
          • decltype(y) int&
      • decltype(auto) (C++14)
        • auto x = 3.5 + 15l;
      • concept auto (C++20),某些类型的共同特征

        域与对象的生命周期

        image.png

        TODO:List构建的生命周期,指向指针,指针被销毁后,list内存内是否还存在