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

婚恋咨询网站运营/十大经典口碑营销案例

婚恋咨询网站运营,十大经典口碑营销案例,试述网站建设的步骤过程,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://www.whsansanxincailiao.cn/news/30284904.html

相关文章:

  • 给有后台的网站做网页/网站推广方案策划
  • wordpress插件残留数据/seoul什么意思
  • 网站没有收录从哪开始做优化/百度竞价排名叫什么
  • ftp发布asp.net网站/品牌推广策划方案案例
  • 智联招聘网站怎么做微招聘信息吗/湖南网站定制
  • 网站制作计算机/站内推广的方法和工具
  • 哪个cms可以做交友网站/阿里指数查询
  • 苏州市相城区建设局网站/seo研究协会网
  • 网站活动模板/关键词查询工具
  • 移动网站建设生要女/关键词排名网站
  • 长沙 外贸网站建设公司价格/腾讯会议价格
  • 网站建设-设计/百度推广后台登录入口
  • 宁德市路桥建设有限公司网站/优化游戏卡顿的软件
  • 网站开发 报刊/嘉兴seo计费管理
  • 临沂网站建设哪家专业/香港服务器
  • 网页设计师认证/关键词优化软件
  • 学校做网站需要什么/2023知名品牌营销案例100例
  • 网站推广营销公司/巨量算数数据分析入口
  • 网站正常打开速度/营销型网站建设团队
  • 政务公开和网站建设工作的建议/查询网站信息
  • 优质聊城做网站公司/网络推广公司怎么找客户
  • Gzip 网站 能够压缩图片吗/奶茶的营销推广软文
  • 杭州富阳网站建设/网站友情链接是什么
  • 网站建设与规划试卷/百度搜索次数统计
  • 在网站添加邮箱/谷歌seo排名优化服务
  • java网站开发 csdn/百度指数查询官网入口登录
  • 昆山哪里有做网站的/今日重大新闻头条财经
  • 局域网怎么建立/谷歌推广seo
  • 重庆黄埔建设集团网站/百度seo排名优化是什么
  • 吾爱网站/夸克搜索引擎