C++变量限定

编程入门 行业动态 更新时间:2024-10-09 15:20:02

C++<a href=https://www.elefans.com/category/jswz/34/1771380.html style=变量限定"/>

C++变量限定

C++的变量限定指可以在变量类型的基础上加上特殊的限定条件,主要包括:是不是const,是不是volatile,是左值还是右值,是不是引用,是左值引用还是右值引用,等等。

1. 为什么要研究这个东西

主要是c++11以后,移动构造(左值右值的区分,std:move()接口),类型推断(模板,auto)等特性,都涉及到了这些东西,如果这些东西搞不明白,很难理解这些语法特性。

2. 如何理解这些限定

这是一个大课题,我们先用一句话概况一下:所有语法都是为了语义。这么说完你可能还是啥都没理解,首先到底语义是个啥,不要着急,后面我们会一直重复这句话,最后回头来看,你肯定会有更深的理解。

下面步入细节,先来看看编译器是如何保存这些限定的吧,编译器对每一个变量都对应一个条目,大概是这样:(只是为了举例,别较真儿)

item变量名内存地址是否const是否volatile左值还是右值引用类型
举例

a

0x100001

是/否

是/否lvalue/rvaluenon/&/&&

注意:

1. 变量的值可以通过内存地址读到,没写到里面

2. 其实有条目的都是左值,右值只是赋值过程中一种临时形态,但为了方便,写到里面了

这样就有了下面这张图:(相信不用解释你也能懂)

通过排列组合,我们很容易得到到底有多少种限定情况:2x2x3 + 2x2x1 = 16。(引用只能是左值,所以不是全组合)

下面就写出这16种限定看看:

 50   int a = 1;51 52   int t1 = a;53   int &t2 = a;54   int &&t3 = std::move(a);55   2; //t456   volatile int t5 = a;57   volatile int &t6 = a;58   volatile int &&t7 = std::move(a);59   std::move(t5); //t860   const int t9 = a;61   const int &t10 = a;62   const int &&t11 = std::move(a);63   std::move(t9); //t1264   const volatile int t13 = a;65   const volatile int &t14 = a;66   const volatile int &&t15 = std::move(a);67   std::move(t13); //t1668   // 不考虑volatile69   int tt1 = a;70   int &tt2 = a;71   int &&tt3 = std::move(a);72   2; //tt473   const int tt5= a;74   const int &tt6 = a;75   const int &&tt7 = std::move(a);76   std::move(tt5); //tt877   //再不考虑const78   int ttt1 = a;79   int &ttt2 = a;80   int &&ttt3 = std::move(a);81   2; //ttt4

注意:

1. 上面也提到了,右值只是一个中间结果,所以没有右值这种类型,只有右值引用,而右值引用本身是个左值。

2. volatile是从C里面继承下来的,告诉编译器不要对其进行寄存器优化(注意,这句话就是语义),这个只有底层编程会用的,不在这里过多讨论,这样还剩下8种。

3. 如果进一步把const也忽略,那就只有4种了,它们是左值/右值,左值引用/右值引用/非引用的区别。

或许你对std::move()了解甚少,但在解释它之前,我们先来复习一下:传值与传引用

从宏观上看,程序运行的过程,就是不断复制数据的过程(=号两边,复制构造,实参传递给形参,函数返回,变量放入容器等等),类型限定也大都发生在复制的过程中,也就是你不能把某种限定的变量,复制给另一种特定类型的变量,最常见的const变量不能给non-const引用、左值引用不能绑定右值等。

好像扯远了,其实我想说的是,在数据复制过程中,首先要分清是传值还是传引用!

如果是传值,好了,你是大爷,有钱人,想出错都难。

因为新数据与源数据只是一次交易,后面就再也没关系了,源数据不会被改变,新数据的限定条件完全自己决定。

从代码上看,如果等式左边是int a = ,那右边可以是任何代表int的变量,或者可以隐式转成int的变量,所有限定条件都不影响,且只要代码编译过,基本不会出错。

 28   int a = 0;29   int b = a;30   int c = std::move(a);31 32   int a2 = 0;33   int &d = a2;34   int e = d;35   int f = std::move(d);36 37 38   const int a3 = 0;39   int g = a3;40   int h = std::move(a3);

std::move()只有在

references and cv-qualifiers,还有lvalue和rvalue的区别:

 11   int a = 2;12   const int b = a;13   volatile int c = a;14   int &d = a;15   const volatile int &e = a;16   int &&f = std::move(a);

程序运行过程,就是不断复制数据的过程,在代码中,最常见的操作就是把一个值复制给另一个值,虽然对应到内存上,都是二进制的拷贝,但在编译器中,由于各种各样的原因,还保留着这组二进制值的某些特性。那复制过程中,要不要保留这些特性呢?在没有类型推断之前,这个问题还比较简单,新的类型是要完全定义出来的,所以程序员必须要指定是否有某种限定(一般没有写,会有一个默认值,比如没有const那就是非const,没有引用,那就是值,没有写右值那就是左值等等)。但有了类型推导后,问题就复杂了,尤其是原值并不是默认值,而新值想用默认值的时候:

 19   int a = 1;20   auto &b = a; //增加引用特性,可以21   const auto &c = a; //增加const和引用,可以22 23   const int d = 2;24   auto e = 2; //e是否要保留const属性?不好决策,实际上是没有25   e++;26   auto &f = d; //f必须保留const属性27 //  f++;28 29   int g = 0;30   int &h = g;31   auto i = h;// i是否是g的引用,还是对应另一片内存?实际上对应另一片内存32   i++;33   cout << g << endl;35   auto j = std::move(g);36 //  int &&k = j; j是左值不是右值

从上面的例子可以看出,auto作为类型推导时,不会保留references and cv-qualifiers,还有lvalue和rvalue。

要想保留这些属性,必须要使用decltype(auto)作为类型推导标识符:

 19   int a = 1;20   auto &b = a; 21   const auto &c = a; 22 23   const int d = 2;24   auto e = d; 25   e++;26   decltype(auto) e2 = d;27 //  e2++; 编译失败,保留了const属性28   auto &f = d; 29 //  f++;30 31   int g = 0;32   int &h = g;33   auto i = h;34   i++;35   cout << g << endl; //036   decltype(auto) i2 = h;37   i2++;38   cout << g << endl; //1 保留了引用属性39 

更多推荐

C++变量限定

本文发布于:2024-02-28 08:04:22,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1768739.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:变量

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!