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

保定市网站建设_网站建设公司_定制开发_seo优化

网站商城系统,网站发布和推广,网站开发培训 从0,中国域名网官网前言 考虑存在这样一个类如HeavyObject#xff0c;其拷贝赋值操作比较耗时#xff0c;通常你在使用函数返回这个类的一个对象时会习惯使用哪一种方式#xff1f;或者会根据具体场景选择某一种方式#xff1f; // style 1 HeavyObject func(Args param);// style 2 bool f…前言 考虑存在这样一个类如HeavyObject其拷贝赋值操作比较耗时通常你在使用函数返回这个类的一个对象时会习惯使用哪一种方式或者会根据具体场景选择某一种方式 // style 1 HeavyObject func(Args param);// style 2 bool func(HeavyObject* ptr, Args param); 上面的两种方式都能过到同样的目的但直观上的使用体验的差别也是非常明显的 style 1只需要一行代码而style 2需要两行代码 // style 1 HeavyObject obj func(params);// style 2 HeavyObject obj; func(obj, params); 但是能达到同样的目的消耗的成本却未必是一样的这取决于多个因素比如编译器支持的特性、C语言标准的规范强制性、多团队多环境开发等等。 看起来style 2虽然使用时需要写两行代码但函数内部的成本却是确定的只会取决于你当前的编译器外部即使采用不同的编译器进行函数调用也并不会有多余的时间开销和稳定性问题。比如func内部使用clanglibc编译外部调用的编译环境为gccgnustl或者vc除了函数调用开销不用担心其它性能开销以及由于编译环境不同会崩溃问题。 因此这里我主要剖析一下style 1背后开发者需要关注的点。 RVO RVO是Return Value Optimization的缩写即返回值优化NRVO就是具名的返回值优化为RVO的一个变种此特性从C11开始支持也就是说C98、C03都是没有将此优化特性写到标准中的不过少量编译器在开发过程中也会支持RVO优化如IBM Compiler比如微软是从Visual Studio 2010才开始支持的。 仍然以上述的HeavyObject类为例为了更清晰的了解编译器的行为这里实现了构造/析构及拷贝构造、赋值操作、右值构造函数如下 class HeavyObject { public:HeavyObject() { cout Constructor\n; }~HeavyObject() { cout Destructor\n; }HeavyObject(HeavyObject const) { cout Copy Constructor\n; }HeavyObject operator(HeavyObject const) { cout Assignment Operator\n; return *this; }HeavyObject(HeavyObject) { cout Move Constructor\n; } private:// many members omitted... }; 编译环境 AppleClang 10.0.1.10010046 * 第一种使用方式 HeavyObject func() {return HeavyObject(); }// call HeavyObject o func(); 按照以往对C的理解HeavyObject类的构造析构顺序应该为 Constructor Copy Constructor Destructor Destructor 但是实际运行后的输出结果却为 Constructor Destructor 实际运行中少了一次拷贝构造和析构的开销编译器帮助我们作了优化。 于是我反汇编了一下 0000000100000f60 __Z4funcv:100000f60: 55 push %rbp100000f61: 48 89 e5 mov %rsp,%rbp100000f64: 48 83 ec 10 sub $0x10,%rsp100000f68: 48 89 f8 mov %rdi,%rax100000f6b: 48 89 45 f8 mov %rax,-0x8(%rbp)100000f6f: e8 0c 00 00 00 callq 100000f80 __ZN11HeavyObjectC1Ev100000f74: 48 8b 45 f8 mov -0x8(%rbp),%rax100000f78: 48 83 c4 10 add $0x10,%rsp100000f7c: 5d pop %rbp100000f7d: c3 retq 100000f7e: 66 90 xchg %ax,%ax 上述汇编代码中的__Z4funcv即func()函数__ZN11HeavyObjectC1Ev即HeavyObject::HeavyObject()。 不同编译器的C修饰规则略有不同。 实际上这里就是先创建外部的对象再将外部对象的地址作为参数传给函数func类似style 2方式。 * 第二种使用方式 HeavyObject func() {HeavyObject o;return o; }// call HeavyObject o func(); 运行上述调用代码的结果为 Constructor Destructor 与第一种使用方式的结果相同这里编译器实际做了NRVO来看一下反汇编 0000000100000f40 __Z4funcv: // func()100000f40: 55 push %rbp100000f41: 48 89 e5 mov %rsp,%rbp100000f44: 48 83 ec 20 sub $0x20,%rsp100000f48: 48 89 f8 mov %rdi,%rax100000f4b: c6 45 ff 00 movb $0x0,-0x1(%rbp)100000f4f: 48 89 7d f0 mov %rdi,-0x10(%rbp)100000f53: 48 89 45 e8 mov %rax,-0x18(%rbp)100000f57: e8 24 00 00 00 callq 100000f80 __ZN11HeavyObjectC1Ev // HeavyObject::HeavyObject()100000f5c: c6 45 ff 01 movb $0x1,-0x1(%rbp)100000f60: f6 45 ff 01 testb $0x1,-0x1(%rbp)100000f64: 0f 85 09 00 00 00 jne 100000f73 __Z4funcv0x33100000f6a: 48 8b 7d f0 mov -0x10(%rbp),%rdi100000f6e: e8 2d 00 00 00 callq 100000fa0 __ZN11HeavyObjectD1Ev // HeavyObject::~HeavyObject()100000f73: 48 8b 45 e8 mov -0x18(%rbp),%rax100000f77: 48 83 c4 20 add $0x20,%rsp100000f7b: 5d pop %rbp100000f7c: c3 retq 100000f7d: 0f 1f 00 nopl (%rax) 从上面的汇编代码可以看到返回一个具名的本地对象时编译器优化操作如第一种使用方式一样直接在外部对象的指针上执行构造函数只是如果构造失败时还会再调用析构函数。 以上两种使用方式编译器所做的优化非常相近两种方式的共同点都是返回本地的一个对象那么当本地存在多个对象且需要根据条件选择返回某个对象时结果会是如何呢 * 第三种使用方式 HeavyObject dummy(int index) {HeavyObject o[2];return o[index]; }// call HeavyObject o dummy(1); 运行后的结果为 Constructor Constructor Copy Constructor Destructor Destructor Destructor 从运行的结果可以看到没有做RVO优化此时调用了拷贝构造函数。 从上述三种实现方式可以看到如果你的函数实现功能比较单一比如只会对一个对象进行操作并返回时编译器会进行RVO优化如果函数实现比较复杂可能会涉及操作多个对象并不确定返回哪个对象时编译器将不做RVO优化此时函数返回时会调用类的拷贝构造函数。 但是当只存在一个本地对象时编译器一定会做RVO优化吗 * 第四种使用方式 HeavyObject func() {return std::move(HeavyObject()); }// call HeavyObject o func(); 实际运行输出的结果是 Constructor Move Constructor Destructor Destructor 上述的函数实现直接返回临时对象的右值引用从实际的运行结果来看调用了Move构造函数与第一种使用方式运行的结果明显不同并不是我期望的只调用一次构造函数和析构函数也就是说编译器没有做RVO。 * 第五种使用方式 HeavyObject func() {HeavyObject o;return static_castHeavyObject(o); }// call HeavyObject o func(); 实际运行输出的结果是 Constructor Copy Constructor Destructor Destructor 上述的函数实现直接返回本地对象的引用实际运行结果仍然调用了拷贝构造函数并不是期望的只调用一次构造和析构函数也就是说编译器并没有做RVO。 从上述两种使用方式可以看到当返回一个对象时且对象类型与返回类型不一致时编译器将不做RVO。实际上C标准文档中有如下描述 in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value 总结 两种style代码的性能可能会不一样当你非常确定你的代码的开发环境及编译器的支持特性如RVO以及使用者的接入环境时建议使用style 1否则建议使用style 2RVO的编译器优化特性需要相对比较严格的限制使用style 1时较复杂的函数实现可能并不会如你期望的使用RVO优化 作者lifesider 原文链接  本文为阿里云原创内容未经允许不得转载
http://www.ihoyoo.com/news/72289.html

相关文章:

  • 做茶歇的网站wordpress 主题 数据
  • php 开发手机网站建设微分销系统哪家比较好
  • 个人性质网站电影网站怎么建设
  • 河南省城乡住房建设厅网站wordpress主题开发ide
  • wordpress 网站统计直播系统程序
  • 不同类型网站优化用dw制作个人简介网页教程
  • 重庆綦江网站制作公司哪家专业永久域名查询
  • 律所网站建设国队男子接力赛西安网约车租赁公司哪家好
  • 什邡网站建设公司炫酷的动画网站
  • 站长工具大全wordpress 自带模板下载
  • 做网站用什么源码好元素领域wordpress
  • 群晖ds1817做网站淘宝怎么提高关键词搜索排名
  • ios风格网站模板展会搭建公司有哪些
  • wordpress培训类网站模板下载php网站开发经典教材
  • python可以做网站开发吗中文 域名的网站
  • 工程建设监理网站定制开发软件税率
  • 网页制作和网站开发怎么做卖衣服网站
  • 网站建设分金手指排名十七随申行是国企嘛?
  • 上传的网站打不开搜索推广平台有哪些
  • 长沙手机网站建设哪些石家庄做商城网站的公司
  • 网站开发用户需求说明书网站备案接入商名称
  • 苏州公司网站设计普宁17网站一起做网店
  • 服务网站备案在360网站上怎么做推广
  • 外贸网站平台都有哪些平台威海团购网站建设
  • 做网站应该掌握的技术吴中seo页面优化推广
  • 网站源码模板南京口碑最好的装修公司
  • 做静态网站成本沈阳定制网络机箱机柜
  • 做外贸必须建网站吗手机浏览器
  • 怎样做信息收费网站百度会员
  • 做win精简系统的网站东吴钢结构网架公司