[ C++ ] | C++11 从左值引用到右值引用

(目录占位)

1. 前言:

C++ 11 是在 C++ 98 之后又一个变化比较大的标准。为C++增加了很多东西,其中有一部分是有用的,有一部分是我自认为作用不是很大东西。这一章呢?我们就来说说C++11我,我认为对性能优化最有用的一部分 ---- 右值引用

2. 简单回顾:左值引用

左值?我们现在说说什么是左值?

直接抛结论:能取地址的值或者表达式结果就是左值。左值可以出现在 = 左边,也可以出现在 = 右边,不能仅仅以 = 号来区分左右值。

最开始时候的引用,就是左值引用,在C++的语法层面上,引用是给一个变量起一个别名,是不开辟空间的,目的是为了:减少拷贝,提高效率

我们通常在学习的时候与 指针 对照学习。

语法层面(指针对比引用):

引用在定义的时候必须初始化,指针在定义的时候是可以不初始化的。

引用是没有空引用的,但是指针呢?他是有空指针的,比如C++11之前的NULL和C++11提供的nullptr。

引用是不开辟空间的,但是指针是需要开辟4个字节或者8个字节的空间的。

引用和指针都有一个概念:权限的方法和缩小,首先一说,只有引用和指针有权限的放大和缩小。其他的语法是没有的,我们在学习的时候,千万不要自己创造语法...

权限的放大:
cpp 复制代码
#include <iostream>

int main()
{
    const int a = 10;
    int &b = a; // 权限的放大

    const int c = 20;
    int *p = &c; // 权限的放大
    return 0;
}

变量 a 的权限是 可读, 但是 变量 b 作为变量 a 的引用,权限却是可读可写。

变量 c 的权限是 可读, 但是 变量 p 指向 变量 a,权限却是可读可写。

上面这两种情况都是编译器默认不被允许的。

权限的缩小:
cpp 复制代码
#include <iostream>

int main()
{
    int a = 10;
    const int &b = a; // 权限的缩小

    int c = 20;
    const int *p = &c; // 权限的缩小
    return 0;
}

变量 a 的权限是 可读可写, 但是 变量 b 作为变量 a 的引用,权限是可读。

变量 c 的权限是 可读可写, 但是 变量 p 指向 变量 c,权限是可读。

上面的这两种情况是编译器默认被允许的。

小结:

权限的放大是不被允许的,但是权限的缩小是被允许的。

权限的放大和缩小都是语法层面的概念,都是被编译器约束的,我们可以通过强制类型转换来放大或者缩小权限(但是不推荐,因为有风险),都只是为了"骗"过编译器。

汇编层面:

引用和指针是一个的,都是开辟可一块空间,用来保存地址,指针变量就是用来保存指向的对象的地址,引用也是一样的,开辟一块空间,用来保存被起别名的对象的地址。

3. 本章主角:右值引用

相对于左值来说,右值就是不能取地址的值,并且右值是不能出现在 = 号的左边的。

自定义类型的右值常见的两种形式 : 临时对象 匿名对象

C++11 对右值又做了细分:纯右值(内置类型) 和将亡值(自定义类型),我们的主要研究对象就是:将亡值(自定义类型)

编译器在进化过程中,将 拷贝构造 + 构造 优化成 直接构造

比如说在函数栈帧内返回一个比较大的对象的时候,右值引用的价值就极大了。

{

原来: 跨行的:构造 + 拷贝构造

现在: 跨行的:构造 + 移动构造

}

减少了一次拷贝,还是很可观的。

移动构造,移动赋值

有了移动构造之后: 返回时先拷贝构造生成临时对象,用临时对象移动构造

如果 "析构函数","拷贝构造","拷贝赋值" 都没有实现编译器就会自动生成 "移动构造"

编译器生成的移动构造:内置类型去值拷贝,自定义类型去调用它自己的移动构造

为什么?

需要显式写析构 ,说明有资源要释放,说明需要显式写拷贝构造重载

说明要显式写移动构造移动赋值

要么都自己写,要么都编译器自己生成。

4. 左值引用和右值引用

这个部分我们主要讨论一下,左值引用是否能引用右值,右值引用是否能引用左值,就是是否能交叉?

先看右值引用能否引用左值?

但是这样:const 左值引用 可以给引用右值 是可以的

除了这样,我们还可以通过强制类型转换来让左值引用引用右值,右值引用引用左值。

5. 小结

左值引用和右值引用的目的都是为了:减少拷贝,提高效率。但是他们都是编译器层面的概念,是可以通过强制类型转化来转化的(骗编译器,不建议)。

相关推荐
I AM_SUN5 分钟前
98. 验证二叉搜索树
数据结构·c++·算法·leetcode
tmacfrank13 分钟前
Java 原生网络编程(BIO | NIO | Reactor 模式)
java·开发语言·网络
沐土Arvin15 分钟前
深入理解 requestIdleCallback:浏览器空闲时段的性能优化利器
开发语言·前端·javascript·设计模式·html
tyatyatya23 分钟前
MATLAB的神经网络工具箱
开发语言·神经网络·matlab
unityのkiven24 分钟前
C++中析构函数不设为virtual导致内存泄漏示例
开发语言·c++
keke101 小时前
Java【14_3】接口(Comparable和Comparator)、内部类-示例
java·开发语言·servlet
小破农1 小时前
C++篇——多态
开发语言·c++
Q_Q19632884751 小时前
python的漫画网站管理系统
开发语言·spring boot·python·django·flask·node.js·php
言之。1 小时前
Go 语言中接口类型转换为具体类型
开发语言·后端·golang
咖啡の猫1 小时前
JavaScript基础-创建对象的三种方式
开发语言·javascript·ecmascript