C++ | 右值引用与std::move()
右值引用
-
左值:可以被取地址的变量或值
-
右值:无法被修改,无法取地址的值。一般为临时变量。
-
左值引用:
-
常引用,只能指向左值
-
或者通过
const
的方式指向一个右值const int & a = 17;
所以,函数形参定义为
const type & var
时,既可以接受变量,也可以接受右值。如std::vector
的push_back()
:void push_back(const type & val);
如果没有
const
,那v.push_back(17)
这样的代码就无法编译通过了。
-
-
右值引用: 只能指向右值的引用,指向左值则无法通过编译
-
使用右值引用,本质上将一个右值变成了一个左值:
int &&a = 17;
变量
a
是一个左值,所以右值引用是一个左值 -
对于函数形参而言,定义为
type && var
将只接受为右值的实参。
为什么会有右值引用的出现呢?
// 类Obj数据的定义 class Obj{ int _size; char *_buf; };
当我们定义
Obj
类的构造函数时,如果我们想用对象a
来初始化对象b
,有时候初始化后我们还想要继续使用对象a
,那这时候的构造函数就需要将对象a
的数据完全复制给对象b
:Obj(const Obj &o){ _size = o._size; _buf = new char[_size]; for(int i=0;i<_size;i++) _buf[i] = o._buf[i]; }
(这样称为深拷贝。浅拷贝是简单地复制值,包括指针,经过浅拷贝之后的两个指针只是指向了同一个地址;而深拷贝会在堆内存中另外申请空间给新指针或者新引用)
而有的时候对象
a
只是一个临时变量(右值),用完即弃。这时候直接将对象a
的数据移动给对象b
即可:Obj(const Obj &o){ _size = o._size; _buf = o._buf; o._buf = nullptr; }
(注意到,在移动构造函数中,末尾有
o._buf = nullptr
。之所以要将被移动数据的对象中的指针/引用置为空指针,原因是避免在对象a
和对象b
的析构函数中都对该地址进行delete
)但实际上,以上的移动构造函数是无法实现的,因为
const
使得传入对象无法被修改。因此,为了实现移动构造函数,C++11引入了右值引用:Obj(Obj && o){ _size = o._size; _buf = o._buf; o._buf = nullptr; }
这样问题就得到解决了。当构造函数时传入参数为右值时,会调用
Obj(Obj && o)
;若是左值,则会调用Obj(const Obj & o)
。此时,又有另外一个问题,如果使用一个对象
a
是一个对象而非一个临时变量,但我依旧想要使用移动数据的方式来构造函数(对象a
在之后不再使用),那该怎么办呢?如果依旧使用
Obj b(a)
来构造,那还是会复制构造。要使用移动构造,就得使用某种方法将对象a
变成右值。而函数std::move()
就起到这个作用:std::move(var)
--- 作用是类型转换:接受一个左值作为参数,返回其右值引用所以此时使用
Obj b(std::move(a))
,就用移动构造初始化了对象b
很多类的成员函数实际上都实现了这两种方法,比如vector的push_back():
// std::vector方法定义 void push_back(const type & value); void push_back(type && value); vector<string> vs; string str = "hello world"; vs.push_back(str); // 此时是传入左值,push_back会深拷贝str vs.push_back(std::move(str)); // 此时传入了右值,push_back浅拷贝str作为vs中的元素 // 同时str被置为空,不能再被使用
-
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!