learncpp-12 复合类型:引用和指针

12 复合类型:引用和指针

12.1 复合数据类型介绍

  • 函数也是一种复合数据类型

12.2 左值和右值

  • 表达式除了可以产生值和副作用,还可以计算为对象或函数
  • C++中的所有表达式都有两个属性:类型值类别
    • 表达式的类型就是计算表达式得出的值、对象、函数的类型
    • 表达式的类型必须在编译时可确定,否则类型检查和类型推导将不起作用
    • 表达式的值可以在编译时确定(如果表达式是constexpr),也可以在运行时确定(如果表达式不是constexpr)
  • 左值表达式和右值表达式
    • 左值表达式的计算结果是一个可识别的对象或函数(可以通过标识符、引用、指针进行访问,并且具有比表达式更长的生存期);右值表达式的计算结果是
    • 左值表达式又分为可以修改的左值表达式和不可修改的左值表达式
    • 右值表达式是不可识别的(这意味着它们必须立即使用),并且只存在于使用它们的表达式的范围内
    • 只有左值表达式可以使用&运算符进行取地址的操作
    • 左值表达式可以隐式转换为右值表达式
      int x{5};
      int y{x};// x is an lvalue expression
      

12.3 左值引用

  • 引用就是现有对象的别名,引用一旦被定义,那么对引用的任何操作都会作用于被引用的对象(引用本质上和被引用的对象相同)
  • 左值引用就是左值(例如一个变量)的别名
  • 通过在类型声明中使用&来声明一个左值引用类型
  • 左值引用变量是一个充当左值(通常是另一个变量)的引用的变量
  • 左值引用必须被初始化
  • 左值引用必须绑定一个可以修改的左值,不能绑定一个不可修改的左值(否则可以通过引用修改这个左值),也不能绑定一个右值
  • void不存在左值引用
  • 引用变量一旦被初始化就不能被改变(不能引用另一个对象)
  • 引用变量遵循和普通变量相同的作用域和生命周期
  • 引用变量的生命周期和被引用变量的生命周期是独立的,哪个先销毁都有可能
  • 当一个对象的引用被销毁时,该对象不会受任何影响
  • 当被引用对象被销毁后,它的引用就称为悬空引用。访问悬空引用会导致未定义的行为
  • 引用不是C++中的对象,引用不需要占用内存
  • 由于引用不是对象,所以不存在引用的引用,因为左值引用必须是一个可识别对象的引用

12.4 const的左值引用

  • 非const左值引用只能绑定一个非const左值;const左值引用可以绑定一个const左值
  • 除非需要修改被引用的对象,否则优先使用const的左值引用,而不是非cosnt的左值引用
  • 非const左值引用不能绑定一个右值;const左值引用可以绑定一个右值(实际上是一个临时对象被创建并用这个右值初始化,然后const左值引用绑定这个临时对象)
  • const左值引用可以绑定不同类型的对象,只要对象的类型可以隐式转换成引用的类型
  • 当一个const左值引用直接绑定到一个临时对象时,临时对象的生存期会被延长以匹配引用的生存期
  • 非const左值引用只能绑定可修改的左值;const左值引用可以绑定可修改左值、不可修改左值、右值
  • constexpr引用只能绑定到全局变量或者静态局部变量(不能绑定到局部变量),因为编译器知道全局变量或者静态局部变量在内存中的实例化地址,因此这些内存地址可以看做是编译时常量
  • 当定义一个const变量的constexpr引用时,需要同时使用constexpr和const

12.5 左值引用传递

  • 使用引用传递可以将实参传递给函数而不是将实参拷贝一份给函数的形参
  • 使用值传递时,改变函数形参不会影响实参的值;而使用引用传递时,改变形参(前提是非const引用)实际上就是在改变实参
  • 因为非const引用只能绑定可修改的左值(或者说非const的变量),所以通过非const引用传递时只能接收可修改的左值作为实参,不能接收const左值和右值

12.6 const左值引用传递

  • 使用const引用传递时,不仅避免了实参的拷贝,还保证了被引用的对象不会被修改
  • 最好使用const引用传递而不是非const引用传递,除非有特殊原因需要修改实参的值
  • class类型的拷贝开销很大,因此一般使用引用传递;基本数据类型的拷贝开销很小,因此一般使用值传递
  • 对于拷贝开销低的对象使用值传递;对于拷贝开销高的对象使用引用传递
  • 优先使用std::string_view传递字符串参数(值传递)而不是const str::string&,除非函数调用了需要C风格字符串或者str::string参数的其他函数

如果实参的类型与形参的类型不匹配,则编译器会尝试隐式转换实参以匹配形参的类型(在这个过程中会创建一个形参类型的临时对象)
创建/拷贝一个std::string_view对象的代价很低,因为不会拷贝它正在查看的字符串
创建/拷贝一个std::string的代价可能很昂贵,因为每个str::string对象都会拷贝一个字符串
因此,std::string_view处理std::stringstd::string_viewC风格字符串这三种实参时开销都不大;而const std::string&只有处理std::string这种实参时开销不大
并且,由于std::string_view是一个普通对象,所以可以直接访问它正在查看的字符串;而const std::string&参数在访问字符串之前需要额外步骤来获取被引用的对象

posted @ 2024-07-22 22:21  dengkang1122  阅读(0)  评论(0编辑  收藏  举报