C++变量限定

C++的变量限定指可以在变量类型的基础上加上特殊的限定条件 , 主要包括:是不是const , 是不是 , 是左值还是右值 , 是不是引用 , 是左值引用还是右值引用 , 等等 。
1. 为什么要研究这个东西
主要是c++11以后 , 移动构造(左值右值的区分 , std:move()接口) , 类型推断(模板 , auto)等特性 , 都涉及到了这些东西 , 如果这些东西搞不明白 , 很难理解这些语法特性 。
2. 如何理解这些限定
这是一个大课题 , 我们先用一句话概况一下:所有语法都是为了语义 。这么说完你可能还是啥都没理解 , 首先到底语义是个啥 , 不要着急 , 后面我们会一直重复这句话 , 最后回头来看 , 你肯定会有更深的理解 。
下面步入细节 , 先来看看编译器是如何保存这些限定的吧 , 编译器对每一个变量都对应一个条目 , 大概是这样:(只是为了举例 , 别较真儿)
item
变量名
内存地址
是否const
是否
左值还是右值
引用类型
举例
是/否
是/否
/
non/&/&&
注意:
1. 变量的值可以通过内存地址读到 , 没写到里面
2. 其实有条目的都是左值 , 右值只是赋值过程中一种临时形态 , 但为了方便 , 写到里面了
这样就有了下面这张图:(相信不用解释你也能懂)
【C++变量限定】通过排列组合 , 我们很容易得到到底有多少种限定情况:2x2x3 + 2x2x1 = 16 。(引用只能是左值 , 所以不是全组合)
下面就写出这16种限定看看:
50int a = 1;51 52int t1 = a;53int &t2 = a;54int &&t3 = std::move(a);552; //t456volatile int t5 = a;57volatile int &t6 = a;58volatile int &&t7 = std::move(a);59std::move(t5); //t860const int t9 = a;61const int &t10 = a;62const int &&t11 = std::move(a);63std::move(t9); //t1264const volatile int t13 = a;65const volatile int &t14 = a;66const volatile int &&t15 = std::move(a);67std::move(t13); //t1668// 不考虑volatile69int tt1 = a;70int &tt2 = a;71int &&tt3 = std::move(a);722; //tt473const int tt5= a;74const int &tt6 = a;75const int &&tt7 = std::move(a);76std::move(tt5); //tt877//再不考虑const78int ttt1 = a;79int &ttt2 = a;80int &&ttt3 = std::move(a);812; //ttt4
注意:
1. 上面也提到了 , 右值只是一个中间结果 , 所以没有右值这种类型 , 只有右值引用 , 而右值引用本身是个左值 。
2. 是从C里面继承下来的 , 告诉编译器不要对其进行寄存器优化(注意 , 这句话就是语义) , 这个只有底层编程会用的 , 不在这里过多讨论 , 这样还剩下8种 。
3. 如果进一步把const也忽略 , 那就只有4种了 , 它们是左值/右值 , 左值引用/右值引用/非引用的区别 。
或许你对std::move()了解甚少 , 但在解释它之前 , 我们先来复习一下:传值与传引用
从宏观上看 , 程序运行的过程 , 就是不断复制数据的过程(=号两边 , 复制构造 , 实参传递给形参 , 函数返回 , 变量放入容器等等) , 类型限定也大都发生在复制的过程中 , 也就是你不能把某种限定的变量 , 复制给另一种特定类型的变量 , 最常见的const变量不能给non-const引用、左值引用不能绑定右值等 。