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

中小网站建设都有哪些方案天元建设集团有限公司是国企还是央企

中小网站建设都有哪些方案,天元建设集团有限公司是国企还是央企,模具东莞网站建设,优秀网络广告案例分析一、什么是左值和右值? 左值和右值在字面上理解,是放在等号左边的值和放在等号右边的值,但是这种字面上的理解是不正确的,实际上,左值是指可以出现在赋值表达式左侧的表达式,通常表示一个具名的、有内存地址…

一、什么是左值和右值?

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

        例如:以下代码,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://www.dtcms.com/wzjs/548786.html

相关文章:

  • 济南想做网站如何自己搭建一个物联网平台
  • 太原网站建设推广服务广州越秀区风险等级
  • 江门网站制作推广广告公司取名字大全免费查询
  • 博物建设公司网站江门网站排名优化
  • 成都建站费用做网站多少
  • 房产网站设计公司wordpress指定ip登陆
  • 网站建设主页济南建站
  • 实力网站建设电话网站建设丨找王科杰效果好
  • 电商网站建设前的市场分析内容如何代做网站
  • 网站空间要多大长沙影楼网站建设
  • 烟台网站推广ppt模板免费下载百度云
  • 网站外链应该怎么做网站开发员的工资
  • 厦门网站建设系统网站建设 概念
  • 网站设计报告总结找公司做网站有什么好处
  • 特级a做爰网站网站建设高手要学多久
  • 晚上网站推广软件免费版seo推广教学
  • 北京网站建设公司公司网站建设合同首付多少钱
  • 贵阳设计网站公司注册网上查名
  • asp.net做三个网站wap712c
  • 网站开发经济可行性分析怎么写网站开发工具js
  • 印尼请人做网站wordpress编辑器转义
  • 如何做购物网站推广怎么iis设置网站
  • 黄浦西安网站建设织梦免费网站模块
  • 网站建设视屏教程农业网站设计
  • 网站建设价值wordpress 插件反复安装
  • 做网站论坛wordpress变色龙主题
  • 自助建站软件自动建站系统网站备案要幕布照
  • 单人网站制作php网站开发实例编程
  • 网站建设 协议书钦州市网站建设
  • 浙江省建设培训中心网站大连网站开发价格