当前位置: 首页 > news >正文

湘潭做网站 磐石网络优质免费crm客户管理系统

湘潭做网站 磐石网络优质,免费crm客户管理系统,用明星名字做网站,外贸网站 在线聊天左值与右值 序言概念左值和右值的划分理解右值引用常量左值引用与右值引用 移动语义引用折叠完美转发 参考资料 序言 虽然平常都算是了解左值,右值的用法,但是好记性不如烂笔头,记下来供大家评鉴,有错改错,有善赞善&a…

左值与右值

  • 序言
  • 概念
    • 左值和右值的划分理解
    • 右值引用
      • 常量左值引用与右值引用
    • 移动语义
    • 引用折叠
    • 完美转发
  • 参考资料

序言

虽然平常都算是了解左值,右值的用法,但是好记性不如烂笔头,记下来供大家评鉴,有错改错,有善赞善,也是对于自己知识的一次梳理。

为什么要分清楚左值和右值?这是因为在理清楚左值和右值,合适为其设置适合的用法,能够有效减少资源开销。

但是,对于一些POD类型的资源,那就无所谓左值右值了,因为拷贝即移动,移动即拷贝。

接下来我以左值和右值的讨论依次简单讲解:左值和右值的概念,右值引用,移动语义,引用折叠,完美转发。明确左值和右值理清楚后,可以使用的主要用法。

:1. 开始看下面之前,需要注意的是!这些除了专业名词之外,基本都是基于个人理解去通俗诠释概括的,想直接看专业且全面的概念就找末尾的参考资料看。
2.以下有比较多的专业词汇,初学者建议慢慢看查询拓展。

概念

左值和右值的划分理解

左值(lvalue)和右值(rvalue)是C++11之前的概念,但是也通用到后面。
C++11及之后,划分为 泛左值(glvalue)、将亡值(xvalue,也称亡值,消亡值)和纯右值(prvalue)

左值(C++11之前):赋值运算“=”左边的变量
右值(C++11之前):赋值运算“=”右边的表达式左值(C++11及之后):非将亡值的泛左值,有地址的变量
右值(C++11及之后):纯右值或者将亡值,生命周期在表达式里。
int a = 15 + 29;
std::cout << &a;	// 0xeffc40
std::cout << &(15 + 29);	//error: Cannot take the address of an rvalue of type 'int'
std::cout << &"xzz";	//0xa16444

以简单的例子,这个a,承载类型的值,自身是有地址的,可以取地址值,这个就是左值。
15 + 29这个表达式的结果是纯右值,不能取地址值。

注:顺带一提,许多普通常量都是纯右值,但是字符串不是,是左值,因为普通常量都是可以用普通的机器码就可以表示其值,但是字符串无法合适表示,所以将其放置在常量区分配内存专门存放。

想必想了解左值和右值的人,估计都看过这个图:
在这里插入图片描述
或者是类似的,基本都是说将亡值泛左值右值的交集。

但是这其实是容易让人摸不着头脑的,但是本质角度上又是能说得过去的。

1. 将亡值被包含在右值这边,是因为其的    生命周期和右值是一样     的,都在一个表达式里面。
2. 将亡值被包含在泛左值这边,是因为其是      匿名对象,有地址,和左值是一样     的。

而上述也引申出了怎么判断将亡值。

将亡值:生命周期在一个表达式里,且是匿名对象有地址。

C++17的临时量实质化也是将亡值。

.

右值引用

右值引用T &&),顾名思义是引用右值的,无论是纯右值还是将亡值

右值引用是C++11引入的,值得注意的是右值引用的变量是个左值

因为其是完全符合左值定义的,众所周知,引用本质上是一种特殊的指针,可以这么认为,指针指向的值是右值,但是指针本身并不是右值。

所以你如果想右值引用 右值引用的变量 这样是不行的:

int &&a = 5;	// 编译正常,可以随意右值引用纯右值
int &&b = a;   	// 编译错误

右值引用的目的是延长将亡值的生命周期,减少资源开销,或者是为了移动语义服务,使其进行资源转移。

struct AA {};
AA createAA() {return AA();
}
int main() {AA &&a = createAA(); 
}

右值引用AA &&a接纳了本来表达式结束就要释放掉资源的匿名对象AA()

并可以任意更改匿名对象的资源。

常量左值引用与右值引用

在C++11之前,负责右值引用(T &&)功能的是常量左值引用(const T &),只不过和右值引用相比,常量左值引用无法修改其值,且只能用于拷贝语义不能用以移动语义
在这里插入图片描述
在这里插入图片描述
可以看出来,常量左值引用右值引用做的事情是一样的。

顺带一提,不建议用右值引用去引用POD类型的纯右值,因为纯右值要想被右值引用,就得先压栈地址,才能给其引用。

从开销上看,不如直接普通的赋值
在这里插入图片描述
在这里插入图片描述
就算单纯只看条数,右值引用用了3条,普通赋值才用了1条,开销一目了然。

.

移动语义

移动语义(Move Semantics)是 C++11 引入的一项重要特性,它使得实例对象的资源不通过拷贝的方式进行转移(除了POD类型)。

移动语义具体化其实就是移动构造函数。

struct Resource { ... }class XZZ 
{
public:...构造或者其他的实例化资源...移动构造函数XZZ(XZZ &&value) {this.m_resource = value.m_resource;value.m_resource = nullptr;}/// 移动赋值函数XZZ &operator =(XZZ &&value) {this.m_resource = value.m_resource;value.m_resource = nullptr;}...
private:Resource *m_resource = nullptr;
}

上面是个简单的例子,主要是为了理解移动是怎么来移动资源的。

如果m_resource不是指针,也可以通过使用std::move强行将value.m_resource转成右值来触发this.m_resource的移动构造,使得两个m_resource的资源进行移动达到同样的效果。

_EXPORT_STD template <class _Ty>
_NODISCARD _MSVC_INTRINSIC constexpr remove_reference_t<_Ty>&& move(_Ty&& _Arg) noexcept {return static_cast<remove_reference_t<_Ty>&&>(_Arg);
}

std::move的效果便是强制将传进来的参数转成右值,一般可以将已经右值引用的变量或者将要释放的类型转成右值(将亡值),实现移动语义的功能。

再次提醒,如果资源是POD类型的,那用移动语义其实没有意义,因为移动就是拷贝,拷贝就是移动。

另外移动构造什么情况下可以编辑器会提供默认移动构造,什么情况下会弃置默认移动构造只能自己写的,这些内容不在本节重点,感兴趣可自行查看。
.

引用折叠

说回右值引用的类型,左值引用右值引用,或者右值引用左值引用,那到底是左值引用还是右值引用呢?

C++11中引入引用折叠规则(reference collapsing),通过模板或 typedef 中的类型操作可以构成引用的引用,此时适用引用折叠规则:右值引用的右值引用折叠成右值引用,所有其他组合均折叠成左值引用

废话不多说:
C++ 11新特性解析与应用
简单通俗来说,只有右值引用本身,和叠加两次的右值引用,类型才是右值引用类型,否则,含至少一个引用&的都是左值引用

不能直接声明一个超过两个&的类型

int a = 10;
int &&& b = a;	// error: 'b' declared as a reference to a reference

但是如果通过using或者typedef间接声明就可以了

typedef int& intR;
using intRe = int&;int a = 10;
intR && b = a;		// 等同于 int &b = a
intRe && c = a;		// 等同于 int &c = a

有了引用折叠,就可以好好使用类型擦除完美转发参数类型给别的函数或者类。
.

完美转发

所谓完美转发(prefect forwarding),是指在函数模板中,完全依照模板的参数的类型,将参数传递给函数模板中调用的另外一个函数。 ——《C++ 11新特性解析与应用》

完美转发关键点在于:

  1. 函数模板
  2. 函数模板参数类型是 类型&&
  3. 要接收函数模板参数的函数/类,实参用std::forward包装一下
template <typename _Ty, typename... _Type>
_Ty *createClass(_Type&&... args) {return new _Ty(std::forward(args)...);
}

这是个没什么实质意义的模板函数,仅是为了举例。

为什么要用std::forward

是因为右值引用args本身是左值,传进来本身如果是个右值的话,结果给到接收函数是个左值,那就不是“完美”转发了。

_EXPORT_STD template <class _Ty>
_NODISCARD _MSVC_INTRINSIC constexpr _Ty&& forward(remove_reference_t<_Ty>& _Arg) noexcept {return static_cast<_Ty&&>(_Arg);
}_EXPORT_STD template <class _Ty>
_NODISCARD _MSVC_INTRINSIC constexpr _Ty&& forward(remove_reference_t<_Ty>&& _Arg) noexcept {static_assert(!is_lvalue_reference_v<_Ty>, "bad forward call");return static_cast<_Ty&&>(_Arg);
}

所以需要转成右值的类型,而如果是左值的话,因为函数重载引用折叠的缘故,即使通过std::forward也是转成左值类型。

参考资料

《C++ 11新特性解析与应用》
《C/C++ 参考文档》

http://www.wooajung.com/news/478.html

相关文章:

  • 制作微信公众号的网站开发seo服务收费
  • 公司制作网站费用百度最新收录方法
  • 区块链 网站 怎么做江苏网页设计
  • 敦煌做网站 条件网站优化推广公司排名
  • 企业展厅设计公司100%正品保障郑州纯手工seo
  • 重庆企业网站制作外包广州网站建设费用
  • 做网站程序seo培训网
  • 服务好的专业建站公司网站seo优化软件
  • 做app原型的网站新乡seo优化
  • 水果网站建设方案百度seo关键词排名优化软件
  • 市住房和城乡建设委员会政务网站网页广告怎么投放
  • 佛山专业网站建设哪家好恢复2345网址导航
  • 简述网站开发基本流程小红书seo排名帝搜软件
  • 洛阳网络营销推广网站优化公司怎么选
  • 35互联做网站怎么样宁波seo优化公司
  • 阿里巴巴批发网站怎么做营销培训课程
  • 安康网站建设公司西安seo公司
  • 下沙网站制作百度权重排名查询
  • 如何给网站做右侧导航页面seo优化
  • 淄博网站推广公司那些中国数据统计网站
  • wordpress卡在首页七台河网站seo
  • 易县做网站新媒体销售好做吗
  • 成都住建局官网登录入口查询北京网站优化哪家好
  • 好孩子官方网站王建设外包网络推广公司怎么选
  • 北京商城型网站建设百度应用商店app
  • 做网站充值系统搜索引擎app
  • 盐城做网站宁波seo深度优化平台有哪些
  • 最便宜做网站百度广告联盟平台官网
  • 周口市规划建设局网站网站推广的四个阶段
  • 长沙网站简述seo的优化流程