news 2026/7/23 17:43:08

C++引用、左值和右值

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++引用、左值和右值

目录

一,引用

1,函数参数引用传递

2,引用型变量

3,函数返回引用型

二,左值和右值

1,左值和右值

2,常见的左值和右值

(1)变量、字面量

(2)表达式

(3)else

3,纯右值、将亡值

4,取址和解地址

5,引用和const

5,move

6,右值引用

7,转发引用、完美转发

三,拷贝构造和移动构造

1,类默认生成的拷贝构造和移动构造函数

2,noexcept

3,vector的移动扩增


一,引用

1,函数参数引用传递

#include<iostream> using namespace std; void f(int& x) { x--; } int main() { int x=3; f(x); cout<<x; return 0; }

输出2

常见错误:

void f(int& x) { x--; } int main() { f(3); return 0; }

2,引用型变量

#include<iostream> using namespace std; int main() { int x=3; int& x2=x; x2++; cout<<x; return 0; }

输出4

常见错误:

int main() { int& x = 3; return 0; }

3,函数返回引用型

#include<iostream> using namespace std; int& f(int arr[],int id) { if(id>sizeof(arr)/sizeof(int))id=0; return arr[id]; } int main() { int arr[]={1,2,3}; f(arr,1)++; f(arr,10)++; cout<<arr[0]<<arr[1]<<arr[2]; return 0; }

输出233

二,左值和右值

1,左值和右值

(1)左值就是有内存地址的,可以用&取地址,右值是没有内存地址的,也就不能取址。

(2)非const的左值可以放在赋值运算符的左边,const左值不行,右值不行。

int x = 1; // 正确,x是左值,1是右值 1 = x; // 错误 int a = x; // 正确, a是左值 a + 1 = 0; // 错误,a+1是右值

(3)左值和右值描述的其实是变量是否作为一个对象保存在计算机中,和存储的位置是不是在内存中没有绝对的关系

比如左值变量用register修饰,虽然保存在寄存器中,但仍然是左值。而如果对register变量取址,那么它一开始就不会被放入寄存器。

(4)右值分为纯右值、将亡值。

2,常见的左值和右值

(1)变量、字面量

变量是左值,const变量是const左值。

string字面量是const左值,其他字面值是右值

(2)表达式

有的表达式产生的是左值,有的表达式产生的是右值。

int main() { int x = 1, y = 2; x + 1; // 右值 x + y; // 右值 ++x; //左值引用 x++; // 右值 &x; // 右值 x=1; // 左值引用 cout<<x; // 左值引用 int* a; *a; // 左值 a + 1; // 右值 *(a + 1); // 左值 return 0; }

(3)else

一般匿名变量指的就是表达式产生的右值,但也不绝对,例如*(a + 1)这个匿名变量就是左值。

函数是左值。

左值对象的成员是左值。

3,纯右值、将亡值

纯右值:字面量、运算表达式、非引用的函数调用

将亡值:右值引用的函数调用

4,取址和解地址

取址 & 是根据左值得到右值,解地址 * 是根据左值或者右值得到左值。

即取址 & 只能用于左值,而 * 都可以。

5,引用和const

& 作为引用时,是可以用于右值的。

void f(const int &x) { cout << x; } int main() { f(3); return 0; }

即,非const的左值引用、const的左值和右值引用都是可以的,非const的右值引用是不行的

而这居然是可以的:

void f(const int &constant) { cout << constant; const int* const_p = &constant; int* modifier = const_cast<int*>(const_p); (*modifier)++; cout << constant; } int main() { f(3); return 0; }

输出34

而如果是这样:

void f(const int &constant) { const int* const_p = &constant; int* modifier = const_cast<int*>(const_p); (*modifier)++; } int main() { const int x = 3; f(x); cout << x; return 0; }

输出3

说明参数相当于是按值传递的。

换个角度看,f(3)其实是右值引用,f(x)是左值引用。

5,move

move函数可以实现把左值换成右值

template <class _Ty> _NODISCARD constexpr remove_reference_t<_Ty>&& move(_Ty&& _Arg) noexcept { // forward _Arg as movable return static_cast<remove_reference_t<_Ty>&&>(_Arg); }

其实也就是把一个变量本身作为返回值,函数的返回值自然就是右值。

6,右值引用

用&&做单目运算符时,表示右值引用。

用Compiler Explorer可以在线编译代码。

下面2个代码的汇编是一样的:

void f(int &&constant) { return; } int main() { f(3); return 0; }

void f(const int &constant) { return; } int main() { f(3); return 0; }

对于右值,其实只是没有给它取名字而已,和左值变量的主要区别在于内存,而在寄存器处,对于计算来说是一样的。

而右值引用这个新语法,使得我们可以像左值引用一样,直接引用一个变量而不用copy,从而高效引用右值,这就是移动语义、完美转发。

从网上盗了一张图:

7,转发引用、完美转发

(1)转发引用

&&这个符号在 C++ 中身兼两职:

当 && 独立出现时(如 int&&、MyClass&&),它是右值引用。
当 && 出现在模板推导上下文中(如 template<typename T> void f(T&& arg)),它被称为转发引用

(2)完美转发

前面提到了完美转发,这里再做一个辨析。

右值引用是一种数据类型,而完美转发是一种编程技巧。

具体来说,完美转发依赖于转发引用std::forward

三,拷贝构造和移动构造

1,类默认生成的拷贝构造和移动构造函数

参考六个默认函数

2,noexcept

析构函数、移动构造函数、移动赋值运算符、swap函数一般不允许抛出异常。

3,vector的移动扩增

vector添加元素时,可能会发生空间倍增。

发生倍增时,可能发生元素移动,也可能发生元素拷贝。

如果元素类型的移动构造函数有noexcept,即保证了不会抛出异常,那么就采用移动的方式,否则就采用拷贝的方式。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/23 17:42:12

在VMWare虚拟机下创建Openwrt LEDE软路由系统

1. 准备工作 安装VMWare WorkStation 15 Pro(傻瓜式安装, 就不写过程了)下载好Openwrt koolshare镜像 2. 开始操作啦 下载Openwrt koolshare镜像 openwrt-koolshare-mod-v2.31-r10822-50aa0525d1-x86-64-combined-squashfs.vmdk 打开VMWare, 点击创建新的虚拟机, 选择自定义…

作者头像 李华
网站建设 2026/7/23 17:41:28

深度解析TM4C129LNCZAD:从数据手册修订看工业MCU实战应用

1. 项目概述&#xff1a;从一份修订记录看一颗工业级MCU的深度解析在嵌入式开发领域&#xff0c;尤其是工业控制、网络通信和物联网网关这类对稳定性和性能有严苛要求的场景&#xff0c;一颗强大的微控制器&#xff08;MCU&#xff09;是系统的“大脑”。而理解这颗“大脑”最权…

作者头像 李华
网站建设 2026/7/23 17:39:34

软路由:AdGuardHome + OpenWRT 让你家的网络无广告无跟踪

目录 一、AdGuardHome 简介 二、先展示一下我家使用 AdGuardHome 一个月内的成果 二、如何使用AdGuardHome & AdGuardHome 拦截规则 1、DNS封锁清单 2、目前我订阅的规则 3、自定义过滤规则 一、AdGuardHome 简介 关于软路由如何搭建部署&#xff0c;可阅读我的上一…

作者头像 李华
网站建设 2026/7/23 17:36:43

小程序协同过滤菜谱推荐系统系统

背景随着移动互联网的普及和人们生活节奏的加快&#xff0c;饮食健康与个性化需求日益受到重视。传统的菜谱推荐方式往往基于静态分类或简单搜索&#xff0c;难以满足用户对个性化、多样化的需求。协同过滤算法作为一种成熟的推荐技术&#xff0c;能够通过分析用户历史行为数据…

作者头像 李华