引用
我常常被指针和引用所搞混以至于在c++中经常胡乱使用这两个东西。指针是我比较熟悉的东西,它是一个变量,占有一个内存区域,只不过其中的值是其他变量的地址。引用实际上和指针很相似,我是通过将两者都转换为汇编观察他们的不同,我尝试的内容不多,我最直观的理解是把引用当作一个带有限制的指针:
你无法取得引用的地址,尽管引用是占据内存区域的,这就使得你弄不出引用的引用来。如果观察汇编会发现如果对引用进行取址&操作,返回的是引用所指向的变量的地址
1
2
3
4
5int a;
int& ra = a;
// 两者的输出是相同的
std::cout << &ra;
std::cout << &a;你无法改变一个引用的指向
1
2
3int a, b;
int& ra = a;
ra = b; // 改变了a的值而不是让ra指向了b一般情况下不是NULLABLE的
有了这些限制的情况下,引用指向性的能力减弱了,但是出现错误的概率也减小了1
2
3
4A a;
A* pa = &a;
pa = NULL;
pa->f() // ub
右值引用
这个时候右值引用的概念又让我困惑了,于是我尝试按照wiki上尝试从使用场景出发…1
2A a1, a2, a3;
a1 = a2 + a3; // 假设A重载了+并返回一个A
a2 + a3的结果是一个临时变量,其结果会被拷贝到a1中,其实这个a2 + a3的结果马上就会消亡,此时直接将其值”移动”到a1中似乎是更为合理的,反正不要浪费嘛… 为什么要额外拷贝一下。
然而c++中此时似乎需要有overload = operator来提供移动赋值语义,不然怎么区分拷贝赋值呢,于是就引入了移动构造和移动赋值语句。
说到这我就想起来c++里还有lvalue/prvalue/xvalue/glvalue/rvalue的概念似乎对理解右值引用比较有帮助
1 | glvalue rvalue |
定义里是这么说的,传统左值是带有名字的,可以使用&操作获取地址的值
传统右值呢就是非传统左值。通常是临时变量(运算结果啦 函数返回值啦),字面量(字面量会被用来构造一个临时变量)1
2
3
4
5
6
7
8
9
10class A{};
A f() {
return A();
}
int main() {
A a, a1;
A* pa = &(f()); // error: taking address of temporary [-fpermissive]
}
表达式(expression)是
- 一系列操作符与函数在表达式上运算的结果
- 字面量
- 变量(变量作为表达式时候去掉其引用类型比如int&变为int))
表达式具有类型(type),但不能是引用类型和值类别(value category)
表达式的类型取决于函数运算的结果(把操作符也看做函数运算)
表达式的值类别帮助确定拷贝和移动语义