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

最新章节 第一百四十七章 做视频网站网络营销案例报告

最新章节 第一百四十七章 做视频网站,网络营销案例报告,wordpress用户发文章数量,深圳软装设计公司有哪些一、什么是左值和右值? 左值和右值在字面上理解,是放在等号左边的值和放在等号右边的值,但是这种字面上的理解是不正确的,实际上,左值是指可以出现在赋值表达式左侧的表达式,通常表示一个具名的、有内存地址…

一、什么是左值和右值?

        左值和右值在字面上理解,是放在等号左边的值和放在等号右边的值,但是这种字面上的理解是不正确的,实际上,左值是指可以出现在赋值表达式左侧的表达式,通常表示一个具名的、有内存地址的对象,相反,右值是指只能出现在赋值表达式右侧的表达式,通常是临时的、没有持久内存地址的值。从定义中可以知道,左值和右值的最根本区别就在于是否有值持久的内存。

        例如:以下代码,a和b都是左值,虽然b不能放在等号左边被修改,但是也属于左值,因为其拥有持久的内存,但是getOne的返回值、2、1是右值,因为其没有持久的内存

        由于二者在内存上面的区别,就可以推导出二者另外一个区别:左值可以引用和取地址,右值不能引用和取地址(此处的引用其实是后面的左值引用)。所以,以下代码都是对的

        以上都是对左值进行取地址和引用,以下代码就是错的,因为以下代码在尝试对由右值进行取地址和引用,因为取地址和引用的原理都是需要获取两个对象的地址,右值本没有持久地址,获取右值地址就会报错。

 二、左值引用和右值引用

        在上面,提到过左值是可以引用的,但是右值不能引用,在C++11标准中引入了右值引用的概念,所谓右值引用,就是对右值的引用,使用&&标识,前文所提到的引用其实是特指左值引用。 例如,以下写法都是正确的,可以对右值引用。

        

        同时,通过左值引用和右值引用,可以重载不同的函数,例如下面的func函数,重载了左值引用和右值引用,在调用的时候,可以分别通过传递左值和右值区分二者,至于这样做的意义,文章后面会提到。

void func(int& a){cout << "调用左值引用函数" << endl;
}void func(int&& a){cout << "调用右值引用函数" << endl;
}int main(){int a = 5;func(a);func(5);return 0;
}

 三、移动语义

         假设现在有这样一个场景,有一个即将消亡的对象,需要复制给另外一个对象或者是用来创建一个新的对象,其一般的做法应该是利用该对象拷贝构造一个对象,其中拷贝的过程是按照将亡对象创建对象大小,再将值拷贝到新的对象中,完成拷贝构造,然后再调用将亡对象的析构函数,使其消亡,在这个过程中,新对象需要新的空间以及将亡对象里面的值,而将亡对象希望调用析构释放自身空间,那么可不可以在底层直接将将亡对象的空间给新对象呢?答案是可以的,这就是C++11的新特性——移动语义。将亡对象可能是右值也可能是左值,指的是马上结束生命周期的对象,例如即将出生命周期的左值,函数返回值的右值等。

        移动语义顾名思义,就是将一个将亡对象的资源给转移走,转移的资源可以用于创建新的对象,也可以用于向其他对象赋值。这样做的好处是,将亡值节省了回收资源的成本,创建对象和赋值减少了获取新的资源的成本。

        下面实现了一个很简单的代码,创建一个字符数组对象,分别创建buffer1,buffer2,buffer3,创建方式分别为一般构造,拷贝构造和移动语义构造(因为第三种直接用返回值构造会被编译器优化,所以手动将其再转为右值std::move())

class charBuffer{
public:charBuffer(int size = 10) :_size(size), _buffer(new char[size]){cout << "default constructor" << endl;}charBuffer(const charBuffer& other):_size(other._size),_buffer(new char[other._size]{memcpy(_buffer, other._buffer, other._size);cout << "copy constructor" << endl;}charBuffer(charBuffer&& other) :_size(other._size), _buffer(other._buffer){other._size = 0;other._buffer = nullptr;cout << "move constructor" << endl;}charBuffer& operator=(const charBuffer& other){//如果为自身,返回自身即可if (&other == this)return *this;//1.先尝试分配新的空间char* buffer = new char[other._size];//2.释放原来空间delete[] _buffer;_size = 0;//3.拷贝内容memcpy(buffer, other._buffer, other._size);_buffer = buffer;_size = other._size;cout << "copy assignment" << endl;return *this;}charBuffer& operator=(charBuffer&& other){//如果为自身,返回自身即可if (&other == this)return *this;//1.释放原来空间delete[] _buffer;_size = 0;//2.获取资源_buffer = other._buffer;_size = other._size;//3.将other置为空other._buffer = nullptr;other._size = 0;cout << "move assignment" << endl;return *this;}~charBuffer(){delete[]_buffer;_size = 0;cout << "destructor" << endl;}private:int _size;char* _buffer;
};charBuffer getBuffer(){charBuffer buffer(100);return buffer;
}int main(){charBuffer buffer1(100);charBuffer buffer2(buffer1);charBuffer buffer3 = std::move(getBuffer());return 0;
}

         在除去编译器优化的内容,输出结果符合预期,buffer1使用一般构造,buffer2使用拷贝构造,在getBuffer中的对象使用一般构造,buffer3调用移动语义构造。其中buffer3中的_buffer就是函数中的buffer的_buffer。

         移动语义可以直接获取将亡值的资源,但是,其实并不是所有的类都需要实现移动语义,当一个类中只有基本类型时,其实移动语义的优势并没有那么明显,就不需要实现移动语义。

        而当一个类中维护着一段内存的时候,移动语义的优势就会变得很明显,因为其省去了拷贝内存内容的动作,使得资源可以再利用,例如在C++11的std库容器就广泛地使用了移动语义,因为其可以大大减小维护内存的成本。

四、std::move()

        通过查看move函数的源码,可以发现,其代码其实就只有一行,使用static_cast将一个_Ty类型的值转为_Ty&&,也就是将一个值转为右值引用的形式并返回。

        所以我们上面的代码,创建最后一个对象的代码可以改为以下,可以看到,运行的结果是相同的。

charBuffer buffer3 = static_cast<charBuffer&&>(getBuffer());

五、完美转发

         在上文中,讲到,函数的参数可以根据左值或者右值进行重载,从而执行不同的逻辑。

        那么以下面的代码为例,第一处调用传入左值,第二次调用传入右值,预期结果为打印先打印左值引用,再打印右值引用,但是结果是打印了两次左值引用,其原因是在调用g的时候,传入的是右值引用,但是在g函数中,创建了一个临时对象,就是这个临时对象,使得传入的buffer有了内存,此时的buffer是可以取地址的,所以再去调用f,传入的就是一个左值了。

void f(charBuffer& buffer){cout << "左值引用" << endl;
}void f(charBuffer&& buffer){cout << "右值引用" << endl;
}void g(charBuffer& buffer){f(buffer);
}void g(charBuffer&& buffer){f(buffer);
}

         为了避免因为传参导致右值变为左值,就可以在g内部使用std::static_cast将其强转为右值引用的形式,但是这样做不太优雅,因为C++11提供了一个专门实现该方法的函数std::forward(),所以上面的代码可以改为以下代码,得到预期结果

void f(charBuffer& buffer){cout << "左值引用" << endl;
}void f(charBuffer&& buffer){cout << "右值引用" << endl;
}void g(charBuffer& buffer){f(std::forward<charBuffer&>(buffer));
}void g(charBuffer&& buffer){f(std::forward<charBuffer&&>(buffer));
}int main(){charBuffer buffer1(100);charBuffer buffer2(100);g(buffer1);g(std::move(buffer2));return 0;
}

        但是,以上写法会比较麻烦,当前只有一个参数需要区分左值右值,如果有多个参数需要区分左值右值,那么代码量会成指数倍增长,所以,可以使用函数模板的形式完成这一动作。

        观察到下面的代码中,g的参数是右值引用形式,该形式称为万能引用,即该形式既可以被推导为左值引用,也可以被推导为右值引用(注意:该写法只在定义时参数中起效,在其他地方还是右值引用的含义),这样就可以将参数推导为需要的类型。

void f(charBuffer& buffer){cout << "左值引用" << endl;
}void f(charBuffer&& buffer){cout << "右值引用" << endl;
}template<typename T>
void g(T&& buffer){f(std::forward<T>(buffer));
}int main(){charBuffer buffer1(100);charBuffer buffer2(100);g(buffer1);g(std::move(buffer2));return 0;
}

六、引用折叠规则

        在上面的例子中,出现了万能引用的概念,其是一个右值引用的形式,但是传入的参数本身就是引用,再加上一个万能引用,变成了引用的引用,这在C++中是不允许的,所以C++11中存在一个规则称为引用折叠,两个引用叠加,会将其折叠为一个引用,其折叠规则如下,简单概括就是除了两个右值引用折叠外,其他折叠方式结果都为左值引用。注意:两个左值折叠得到的依然是左值引用,而不是右值引用,右值引用不能被拆为两个左值引用折叠。

         七、std::forward

        和move一样,forward的函数内容也十分简单,就是根据传入的参数,引用类型,对传入参数进行右值引用,再根据引用折叠规则,转为特定引用类型。

        所以上面代码也可以改为以下

template<typename T>
void g(T&& buffer){f(static_cast<T&&>(buffer));
}

笔者有话说

        到此处,本期内容就全部结束了,C++11引入左值引用和右值引用的概念使得C++这门语言变得更加复杂,让程序员的学习成本也变得更高,但是通过引入右值引用和移动语义,使得将亡资源可以被其他对象接手重复利用,提高了资源的利用效率,同时减小了资源请求与释放的开销。这是C++这门语言追求高效率的一种体现,但是这种对效率极致的追求反过来会使得C++的复杂度变得进一步提升。


文章转载自:

http://KeVNfj9b.xpgwz.cn
http://W2JKrdWC.xpgwz.cn
http://AghEclHs.xpgwz.cn
http://eZNSuX5r.xpgwz.cn
http://iw8LpBDv.xpgwz.cn
http://8HpSVDNm.xpgwz.cn
http://L5zS5V0c.xpgwz.cn
http://WYCzKbfe.xpgwz.cn
http://nwluIoCm.xpgwz.cn
http://yxw1E7lu.xpgwz.cn
http://54qCgRAr.xpgwz.cn
http://hHAQHoiq.xpgwz.cn
http://yd9kMw6g.xpgwz.cn
http://VFBnAHUQ.xpgwz.cn
http://hTJCmYcv.xpgwz.cn
http://mfdybOPq.xpgwz.cn
http://RmHFeMM6.xpgwz.cn
http://tUBct9bT.xpgwz.cn
http://42wgwLCa.xpgwz.cn
http://kwckQH1S.xpgwz.cn
http://Yjluekph.xpgwz.cn
http://ZATWxQmx.xpgwz.cn
http://s0xMHSX9.xpgwz.cn
http://RqlS8aiI.xpgwz.cn
http://dJe6bUOG.xpgwz.cn
http://8bqcZzBR.xpgwz.cn
http://hDLxKid6.xpgwz.cn
http://8XBxA50o.xpgwz.cn
http://i0V4vCMa.xpgwz.cn
http://fPUMU7Yl.xpgwz.cn
http://www.dtcms.com/wzjs/745980.html

相关文章:

  • 销售行业怎样做网站wordpres做视频网站
  • 网站组成做破解的网站
  • 有口碑的江苏网站建设射洪县住房和城乡建设局网站
  • 外国旅游网站建设现状门户网站有
  • 上海市单位名称地址大全温州网站建设优化
  • 网站死链西安网站建设罗鑫
  • 站长全网指数查询凡客诚品logo
  • 电子商务网站建设的发展趋势wordpress zhuce邮件
  • 陕西找人做网站多少钱wordpress相关文章源文件
  • 网站制作公司需要什么资质贵阳有没有网站建设公司
  • 怎么去创立一个网站it培训机构都有哪些
  • 熟练掌握网站开发技术向wordpress提交插件
  • 成都交投成高建设公司网站怎么提高网站加载速度
  • 哈密市建设局网站wordpress 全站不刷新
  • dedecms模板站源码wordpress 模版定制
  • 网站域名空间多少钱成都旅游景点攻略自由行攻略
  • 自己制作图片文字图片排名优化公司哪家效果好
  • 网站建设中 敬请期待.重庆璧山网站制作报价
  • 做网站用什么软件方便腾讯云 wordpress教程
  • 北京网站开发哪家好薇网站管理人员队伍建设有待加强
  • 盖州网站优化南京建设网站维护
  • 惠州网站建设 英语百度收录网站怎么做
  • 楚雄网站设计厂家搜索排名哪家好
  • 怎么在网站上加qq自己做简单的网站
  • 电子商务网站建设html网站从新建设影响收录么
  • 企业做网站有哪些好处常州专业网站建设费用
  • 郑州优化网站收费标准wordpress中文版 显示英文版
  • 网站建设费记账公众号制作教程
  • 莱西做网站公司无锡网站建设排名
  • 网站推广方案怎么写的网站建设为了什么