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

免费软件下载公众号北京seo全网营销

免费软件下载公众号,北京seo全网营销,开发做游戏的网站,米绘设计师服务平台目录 1、引言 2、值类别及相关概念 3、左值、右值 4、左值引用、右值引用 5、移动语义 5.1、为什么需要移动语义 5.2、移动语义定义 5.3、转移构造函数 5.4、转移赋值函数 6、标准库函数 std::move 7、完美转发 std::forward VC常用功能开发汇总(专栏文章…

目录

1、引言

2、值类别及相关概念

3、左值、右值

4、左值引用、右值引用

5、移动语义

5.1、为什么需要移动语义

5.2、移动语义定义

5.3、转移构造函数

5.4、转移赋值函数

6、标准库函数 std::move

7、完美转发 std::forward


VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具从入门到精通案例集锦(专栏文章正在更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html       C++11新特性很重要,作为C++开发人员很有必要去学习,不仅笔试面试时会涉及到,开源代码中会大规模的使用。以很多视频会议及直播软件都在使用的开源WebRTC项目为例,WebRTC代码中大篇幅地使用了C++11及以上的新特性,要读懂其源码,必须要了解这些C++的新特性。所以,接下来一段时间我将结合工作实践,给大家详细讲解一下C++11的新特性,以供借鉴或参考。

1、引言

       C++11引入了对象移动的概念,是一种移动而非拷贝对象的能力,移动对象可以有效地提高程序的性能。

       为了支持移动操作,C++11引入了一种新的引用类型 - 右值引用(rvalue references)。所谓右值引用,是必须要绑定到右值的引用,通过&&操作符获得右值引用。今天就来详细讲讲左值、左值引用、右值、右值引用相关的内容。

2、值类别及相关概念

       在C++11中,值类别主要分为左值、左值引用、右值与右值引用。左值引用是绑定到左值的应用,右值引用则是绑定到右值的引用。当右值引用T&&出现在模板函数的参数中,T是模板类型,T&&则是万能引用。万能引用可以接收左值参数,也可以接收右值参数。然后在推导函数参数类型时,可能会发生引用折叠。还会涉及到标准库函数std::move和std::forward。

3、左值、右值

       在C语言中,我们常常会提起左值(lvalue)、右值(rvalue)这样的称呼。一个最为典型的判别方法就是,在赋值表达式中,出现在等号左边的就是“左值”,而在等号右边的,则称为“右值”。如:

int b = 1;
int c = 2;
int a = a + b;

在这个赋值表达式中,a就是一个左值,而b + c则是一个右值。

       不过C++中还有一个被广泛认同的说法,那就是可以取地址的、有名字的就是左值,反之,不能取地址的、没有名字的就是右值。那么这个加法赋值表达式中,&a是允许的操作,但&(b + c)这样的操作则不会通过编译。因此a是一个左值,(b + c)是一个右值。相对于左值,右值表示字面常量、表达式、函数的非引用返回值等。

       这里总结一下,什么是左值:

1)能被赋值(充分非必要条件),左值不一定能被赋值,比如const变量,智能在初始化时赋初值,后续不能赋值
2)能取址(充分非必要条件),左值不一定能取址,比如C语言中的register变量:register int i= 3,C++11已经取消了对register的支持,编译时会忽略。再比如C语言中的位域变量是不能取址的:
struct St{ int m:3;} St st; st.m = 3; 指定int型成员m占3个字节。
3)可以初始化左值引用(必要不充分条件),左值可以初始化左值引用,比如:int m = 3; int& n = m;,右值不能初始化左值引用,比如:const int& m = 3; 因为3是右值,不能初始化左值引用,所以编译会报错。
4)字面量属于纯右值,比如1,2,3等立即数就属于字面量,注意,常量字符串“xyz”是左值,可以对该字符串进行取址,即&"xyz"。
5)将亡值可以偷其中的资源。函数的返回值,则是纯右值,返回右值引用,比如std::move函数。

4、左值引用、右值引用

       左值引用是对一个左值进行引用的类型,右值引用则是对一个右值进行引用的类型。左值引用和右值引用都是属于引用类型。无论是声明一个左值引用还是右值引用,都必须立即进行初始化。而其原因可以理解为是引用类型本身自己并不拥有所绑定对象的内存,只是该对象的一个别名。

        左值引用是具名变量值的别名,而右值引用则是不具名(匿名)变量的别名。

        左值引用示例:

int &a = 2;       // 左值引用绑定到右值,编译失败, err
int b = 2;        // 非常量左值
const int &c = b; // 常量左值引用绑定到非常量左值,编译通过, ok
const int d = 2;  // 常量左值
const int &e = c; // 常量左值引用绑定到常量左值,编译通过, ok
const int &b = 2; // 常量左值引用绑定到右值,编程通过, ok

“const 类型 &”为 “万能”的引用类型,它可以接受非常量左值、常量左值、右值对其进行初始化;

       右值引用,使用&&表示:

int && r1 = 22;
int x = 5;
int y = 8;
int && r2 = x + y;
T && a = ReturnRvalue();

       通常情况下,右值引用是不能够绑定到任何的左值的:

int c;
int && d = c; //err

       下面看一个测试示例:

void process_value(int & i) //参数为左值引用
{cout << "LValue processed: " << i << endl;
}void process_value(int && i) //参数为右值引用
{cout << "RValue processed: " << i << endl;
}int main()
{int a = 0;process_value(a); //LValue processed: 0process_value(1); //RValue processed: 1return 0;
}

5、移动语义

5.1、为什么需要移动语义

       右值引用是用来支持转移语义的。转移语义可以将资源 ( 堆,系统对象等 ) 从一个对象转移到另一个对象,这样能够减少不必要的临时对象的创建、拷贝以及销毁,能够大幅度提高 C++ 应用程序的性能。临时对象的维护 ( 创建和销毁 ) 对性能有严重影响。

       转移语义是和拷贝语义相对的,可以类比文件的剪切与拷贝,当我们将文件从一个目录拷贝到另一个目录时,速度比剪切慢很多。通过转移语义,临时对象中的资源能够转移其它的对象里。

5.2、移动语义定义

       在现有的 C++ 机制中,我们可以定义拷贝构造函数和赋值函数。要实现转移语义,需要定义转移构造函数,还可以定义转移赋值操作符。对于右值的拷贝和赋值会调用转移构造函数和转移赋值操作符。

       如果转移构造函数和转移拷贝操作符没有定义,那么就遵循现有的机制,拷贝构造函数和赋值操作符会被调用。普通的函数和操作符也可以利用右值引用操作符实现转移语义。

5.3、转移构造函数

       先来看个转移构造函数的实例:

class MyString
{
public:MyString(const char *tmp = "abc"){//普通构造函数len = strlen(tmp);  //长度str = new char[len+1]; //堆区申请空间strcpy(str, tmp); //拷贝内容cout << "普通构造函数 str = " << str << endl;}MyString(const MyString &tmp){//拷贝构造函数len = tmp.len;str = new char[len + 1];strcpy(str, tmp.str);cout << "拷贝构造函数 tmp.str = " << tmp.str << endl;}//移动构造函数//参数是非const的右值引用MyString(MyString && t){str = t.str; //拷贝地址,没有重新申请内存len = t.len;//原来指针置空t.str = NULL;cout << "移动构造函数" << endl;}MyString &operator= (const MyString &tmp){//赋值运算符重载函数if(&tmp == this){return *this;}//先释放原来的内存len = 0;delete []str;//重新申请内容len = tmp.len;str = new char[len + 1];strcpy(str, tmp.str);cout << "赋值运算符重载函数 tmp.str = " << tmp.str << endl;return *this;}~MyString(){//析构函数cout << "析构函数: ";if(str != NULL){cout << "已操作delete, str =  " << str;delete []str;str = NULL;len = 0;}cout << endl;}private:char *str = NULL;int len = 0;
};MyString func() //返回普通对象,不是引用
{MyString obj("mike");return obj;
}int main()
{MyString &&tmp = func(); //右值引用接收return 0;
}


和拷贝构造函数类似,有几点需要注意:

1)参数(右值)的符号必须是右值引用符号,即“&&”。
2)参数(右值)不可以是常量,因为我们需要修改右值。
3)参数(右值)的资源链接和标记必须修改,否则,右值的析构函数就会释放资源,转移到新对象的资源也就无效了。

       有了右值引用和转移语义,我们在设计和实现类时,对于需要动态申请大量资源的类,应该设计转移构造函数和转移赋值函数,以提高应用程序的效率。 

5.4、转移赋值函数

         直接看转移赋值函数的实例:

class MyString
{
public:MyString(const char *tmp = "abc"){//普通构造函数len = strlen(tmp);  //长度str = new char[len+1]; //堆区申请空间strcpy(str, tmp); //拷贝内容cout << "普通构造函数 str = " << str << endl;}MyString(const MyString &tmp){//拷贝构造函数len = tmp.len;str = new char[len + 1];strcpy(str, tmp.str);cout << "拷贝构造函数 tmp.str = " << tmp.str << endl;}//移动构造函数//参数是非const的右值引用MyString(MyString && t){str = t.str; //拷贝地址,没有重新申请内存len = t.len;//原来指针置空t.str = NULL;cout << "移动构造函数" << endl;}MyString &operator= (const MyString &tmp){//赋值运算符重载函数if(&tmp == this){return *this;}//先释放原来的内存len = 0;delete []str;//重新申请内容len = tmp.len;str = new char[len + 1];strcpy(str, tmp.str);cout << "赋值运算符重载函数 tmp.str = " << tmp.str << endl;return *this;}//移动赋值函数//参数为非const的右值引用MyString &operator=(MyString &&tmp){if(&tmp == this){return *this;}//先释放原来的内存len = 0;delete []str;//无需重新申请堆区空间len = tmp.len;str = tmp.str; //地址赋值tmp.str = NULL;cout << "移动赋值函数\n";return *this;}~MyString(){//析构函数cout << "析构函数: ";if(str != NULL){cout << "已操作delete, str =  " << str;delete []str;str = NULL;len = 0;}cout << endl;}private:char *str = NULL;int len = 0;
};MyString func() //返回普通对象,不是引用
{MyString obj("mike");return obj;
}int main()
{MyString tmp("abc"); //实例化一个对象tmp = func();return 0;
}

6、标准库函数 std::move

       编译器只对右值引用才能调用转移构造函数和转移赋值函数,而所有命名对象都只能是左值引用,如果已知一个命名对象不再被使用而想对它调用转移构造函数和转移赋值函数,也就是把一个左值引用当做右值引用来使用,怎么做呢?标准库提供了函数 std::move,这个函数以非常简单的方式将左值引用转换为右值引用。

int a;
int &&r1 = a;              // 编译失败
int &&r2 = std::move(a);      // 编译通过

7、完美转发 std::forward

        完美转发适用于这样的场景:需要将一组参数原封不动的传递给另一个函数。“原封不动”不仅仅是参数的值不变,在 C++ 中,除了参数值之外,还有一下两组属性:左值/右值和 const/non-const。完美转发就是在参数传递过程中,所有这些属性和参数值都不能改变,同时,而不产生额外的开销,就好像转发者不存在一样。在泛型函数中,这样的需求非常普遍。

       下面举例说明:

#include <iostream>
using namespace std;template <typename T> void process_value(T & val)
{cout << "T &" << endl;
}template <typename T> void process_value(const T & val)
{cout << "const T &" << endl;
}
//函数 forward_value 是一个泛型函数,它将一个参数传递给另一个函数 process_value
template <typename T> void forward_value(const T& val)
{process_value(val);
}template <typename T> void forward_value(T& val)
{process_value(val);
}int main()
{int a = 0;const int &b = 1;//函数 forward_value 为每一个参数必须重载两种类型,T& 和 const T&forward_value(a); // T&forward_value(b); // const T &forward_value(2); // const T&return 0;
}

        对于一个参数就要重载两次,也就是函数重载的次数和参数的个数是一个正比的关系。这个函数的定义次数对于程序员来说,是非常低效的。

        那C++11是如何解决完美转发的问题的呢?实际上,C++11是通过引入一条所谓“引用折叠”(reference collapsing)的新语言规则,并结合新的模板推导规则来完成完美转发。

typedef const int T;
typedef T & TR;
TR &v = 1; //在C++11中,一旦出现了这样的表达式,就会发生引用折叠,即将复杂的未知表达式折叠为已知的简单表达式

        C++11中的引用折叠规则:

TR的类型定义

声明v的类型

v的实际类型

T &

TR

T &

T &

TR &

T &

T &

TR &&

T &

T &&

TR

T &&

T &&

TR &

T &

T &&

TR &&

T &&

注意,一旦定义中出现了左值引用,引用折叠总是优先将其折叠为左值引用。       C++11中,std::forward可以保存参数的左值或右值特性:

#include <iostream>
using namespace std;template <typename T> void process_value(T & val)
{cout << "T &" << endl;
}template <typename T> void process_value(T && val)
{cout << "T &&" << endl;
}template <typename T> void process_value(const T & val)
{cout << "const T &" << endl;
}template <typename T> void process_value(const T && val)
{cout << "const T &&" << endl;
}//函数 forward_value 是一个泛型函数,它将一个参数传递给另一个函数 process_value
template <typename T> void forward_value(T && val) //参数为右值引用
{process_value( std::forward<T>(val) );//C++11中,std::forward可以保存参数的左值或右值特性
}int main()
{int a = 0;const int &b = 1;forward_value(a); // T &forward_value(b); // const T &forward_value(2); // T &&forward_value( std::move(b) ); // const T &&return 0;
}

文章转载自:
http://dinncolegislative.zfyr.cn
http://dinncomhg.zfyr.cn
http://dinncoperpetuity.zfyr.cn
http://dinncoimbibe.zfyr.cn
http://dinncodangler.zfyr.cn
http://dinncocopygraph.zfyr.cn
http://dinncomorphinomania.zfyr.cn
http://dinncovibraharp.zfyr.cn
http://dinncorepel.zfyr.cn
http://dinncolittlish.zfyr.cn
http://dinncosuperstitionist.zfyr.cn
http://dinncobugs.zfyr.cn
http://dinncorescript.zfyr.cn
http://dinncojaculate.zfyr.cn
http://dinncopainkiller.zfyr.cn
http://dinncotriglot.zfyr.cn
http://dinncosexennium.zfyr.cn
http://dinncoreasonless.zfyr.cn
http://dinncodispassion.zfyr.cn
http://dinncokwh.zfyr.cn
http://dinncodoughnut.zfyr.cn
http://dinncoplanetesimal.zfyr.cn
http://dinncohydrodesulfurization.zfyr.cn
http://dinncogillaroo.zfyr.cn
http://dinncosharebroker.zfyr.cn
http://dinncolavash.zfyr.cn
http://dinncoorins.zfyr.cn
http://dinncoabsquatulation.zfyr.cn
http://dinncoterrifying.zfyr.cn
http://dinncosizzle.zfyr.cn
http://dinncodisconnected.zfyr.cn
http://dinncointerblend.zfyr.cn
http://dinncorabbiteye.zfyr.cn
http://dinncofreestone.zfyr.cn
http://dinncoepazote.zfyr.cn
http://dinncoultramundane.zfyr.cn
http://dinncocalescent.zfyr.cn
http://dinncotautologize.zfyr.cn
http://dinncothenar.zfyr.cn
http://dinnconocturnality.zfyr.cn
http://dinncoreed.zfyr.cn
http://dinncogallow.zfyr.cn
http://dinncophotoinduction.zfyr.cn
http://dinncolatinity.zfyr.cn
http://dinncomanila.zfyr.cn
http://dinncoworthless.zfyr.cn
http://dinncovaginae.zfyr.cn
http://dinncoconcede.zfyr.cn
http://dinncodismay.zfyr.cn
http://dinncovivific.zfyr.cn
http://dinncobroederbond.zfyr.cn
http://dinncoportionless.zfyr.cn
http://dinncojody.zfyr.cn
http://dinncounmercenary.zfyr.cn
http://dinncosuperlunar.zfyr.cn
http://dinncoartillerist.zfyr.cn
http://dinncouneffectual.zfyr.cn
http://dinncosnowswept.zfyr.cn
http://dinncoukulele.zfyr.cn
http://dinncohairstylist.zfyr.cn
http://dinncomolossus.zfyr.cn
http://dinncolaparoscopy.zfyr.cn
http://dinncoblowzy.zfyr.cn
http://dinncoalgidity.zfyr.cn
http://dinncotransvest.zfyr.cn
http://dinncotorpidity.zfyr.cn
http://dinncoironhearted.zfyr.cn
http://dinncocodeine.zfyr.cn
http://dinncoshunt.zfyr.cn
http://dinncororic.zfyr.cn
http://dinncotransitively.zfyr.cn
http://dinncocracking.zfyr.cn
http://dinncorcvs.zfyr.cn
http://dinncoscrub.zfyr.cn
http://dinncobubbleheaded.zfyr.cn
http://dinncoasperse.zfyr.cn
http://dinncodeprecatory.zfyr.cn
http://dinncoseadrome.zfyr.cn
http://dinncospifflicate.zfyr.cn
http://dinnconydia.zfyr.cn
http://dinncolarva.zfyr.cn
http://dinncooutline.zfyr.cn
http://dinncouprising.zfyr.cn
http://dinncoxebec.zfyr.cn
http://dinncogangsterism.zfyr.cn
http://dinncousps.zfyr.cn
http://dinncointersectional.zfyr.cn
http://dinncovolsteadism.zfyr.cn
http://dinncobeau.zfyr.cn
http://dinncosceneman.zfyr.cn
http://dinncohuron.zfyr.cn
http://dinncobaboosh.zfyr.cn
http://dinncosplit.zfyr.cn
http://dinncoamyotrophia.zfyr.cn
http://dinncointerstadial.zfyr.cn
http://dinncomonohydroxy.zfyr.cn
http://dinncoanalgetic.zfyr.cn
http://dinncopantisocracy.zfyr.cn
http://dinncoforefend.zfyr.cn
http://dinncorefrigerator.zfyr.cn
http://www.dinnco.com/news/157325.html

相关文章:

  • 设计素材网站集合网址域名查询ip地址
  • php网站开发前言黑马培训是正规学校吗
  • 做网站没什么用啊老师别人强襄阳seo推广
  • 建设项目经济评价网站公众号怎么推广和引流
  • 网页兼容性站点在线h5免费制作网站
  • 有没有教做熟食的网站最新地址
  • 网站页面设计服务seo服务外包费用
  • 外贸建立网站怎么做web个人网站设计代码
  • 自己做网站销售宣传方式有哪些
  • 技术博客主题wordpress晨阳seo顾问
  • java做的网站很快免费seo关键词优化排名
  • wordpress主题带有推荐功能网站优化外包顾问
  • 网页和网站做哪个好用网页设计模板素材图片
  • 网站建设和网络推广服务公司百度seo排名培训优化
  • 网站设计欣赏移动广告制作公司
  • 诸城企业网站建设搜索关键词的工具
  • 淘宝 网站建设教程优化营商环境指什么
  • 微信网站建设模板淘宝关键词推广
  • 如何做网站啊搜索推广营销
  • 做网站自己装服务器针对本地的免费推广平台
  • 中国空间站24小时直播入口泉州seo按天收费
  • 海口关键词优化报价seo属于运营还是技术
  • 做网站联系网站快速排名
  • 廊坊网站建设-纵横网络+网站网络广告策划
  • 辽宁朝阳网站建设公司广州排名推广
  • 水资源论证网站建设湘潭高新区最新新闻
  • .tv做网站怎么样自有品牌如何推广
  • 网站提供服务商武汉服装seo整站优化方案
  • 做外贸网站服务互联网营销工具有哪些
  • 网站建设与维护实训近期的重大新闻