39

再谈右值引用与移动语义

 5 years ago
source link: http://blog.guoyb.com/2018/07/07/move-again/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

之前在总结C++11新特性的时候,写过一篇文章,专门说到了右值引用、移动语义以及从中牵扯出来的引用折叠和完美转发等概念 《C++11新特性之右值引用与移动》

那篇文章例子很多,仔细阅读后也可以完全理解这几个概念。但是今天我想重新组织下语言,就像面试中被问到“你怎么看待C++中的右值引用和移动语义”,进行一次小总结。当然,如果你最近也正好需要面试,下面的文字可能能帮你梳理一遍思路。

右值引用

右值引用就是对右值的引用(废话),而右值是相对于左值而言的:左值持久,右值短暂。

右值这个概念在C++11之前就已经存在了,比如你写一个 ```5*j=6``` 这样的表达式,就会被编译器提示,不能给右值赋值。

右值引用,是一种 类型 。类型可以用来定义变量,用右值引用这个类型来定义的变量, 是一个左值 。这一点很绕,也是完美转发比较难理解的地方。

std::move

std::move虽然叫move,但是它并没有 实现 任何移动的功能(也就是没有实现移动语义)。

那std::move是干嘛的呢?其实它只是做了一个类型转换:传入一个左值变量,返回其右值引用。

对,就是这么简单。

移动语义

右值引用和左值引用是两种不同的类型,既然是不同的类型,那用作函数参数时,就可以实现 重载 :由具体传入的参数类型来决定调用哪个版本的函数。

如果是右值引用为参数的版本,我们说其拥有 移动语义 ,即,这个函数被批准 窃取 参数的内部资源,而不用做深度拷贝,这样效率较高。但是,移动语义有个重要的限制:

被用作参数的右值引用所指向(绑定)的对象,在移动语义完成之后,内部资源已被“窃取”,不能再被其他地方使用;其只是维持一个可析构可销毁的状态。

移动之后的变量可析构可销毁,由移动语义的实现方保证;移动之后不被其他地方使用,则由移动语义的调用方保证。

所以,说白了,移动语义,就是在C++添加了右值引用这一类型之后,对原有的函数(左值引用,拷贝语义),增加了一个重载的版本。这个版本做出了一些限制(参数调用后可析构可销毁,不可再次使用),也带来了效率提升(比如拷贝指针而非深度拷贝内存块)。而要调用到这个新的重载版本呢,就需要用std::move强制的获得一个右值引用类型变量。

总结

其实就这么点东西。引用折叠和完美转发找时间再说,稍微有点麻烦,而且用到的地方也更少一些。

目前标准库以及protobuf中的类型都已实现了移动语义,基本可以放心使用。如果是自定义的类型,想要使用移动语义,就需要自己去重载右值引用参数版本的带有移动语义的函数了。重载时,要记得需要保证右值引用移动后的可析构可销毁状态~

转载请注明出处: http://blog.guoyb.com/2018/07/07/move-again/

欢迎使用微信扫描下方二维码,关注我的微信公众号TechTalking,技术·生活·思考:

b6niUzu.jpg!web

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK