当前位置: 首页 > 编程日记 > 正文

提高C++性能的编程技术笔记:虚函数、返回值优化+测试代码

虚函数:在以下几个方面,虚函数可能会造成性能损失:构造函数必须初始化vptr(虚函数表);虚函数是通过指针间接调用的,所以必须先得到指向虚函数表的指针,然后再获得正确的函数偏移量;内联是在编译时决定的,编译器不可能把运行时才解析的虚函数设置为内联

无法内联虚函数造成的性能损失最大。

某些情况下,在编译期间解析虚函数的调用是可能的,但这是例外情况。由于在编译期间不能确定所调用的函数所属的对象类型,所以大多数虚函数调用都是在运行期间解析的。编译期间无法解析对内联造成了负面影响。由于内联是在编译期间确定的,所以它需要具体函数的信息,但如果在编译期间不能确定将调用哪个函数,就无法使用内联。

评估虚函数的性能损失就是评估无法内联该函数所造成的损失。这种损失的代价并不固定,它取决于函数的复杂程度和调用频率。一种极端情况是频繁调用的简单函数,它们是内联的最大受益者,若无法内联则会造成重大性能损失。另一极端情况是很少调用的复杂函数。

通过对类选择进行硬编码或者将它作为模板参数来传递,可以避免使用动态绑定。

因为函数调用的动态绑定是继承的结果,所以消除动态绑定的一种方法是用基于模板的设计来替代继承。模板把解析的步骤从运行期间提前到编译期间,从这个意义上说,模板提高了性能。而对于我们所关心的编译时间,适当增加也是可以接受的。

返回值优化通过转换源代码和消除对象的创建来加快源代码的执行速度,这种优化称为返回值优化(Return Value Optimization, RVO)

编译器优化要保证原来计算的正确性。然而对于RVO来说,这一点并不总是易于实现的。既然RVO不是强制执行的,编译器就不会对复杂的函数执行RVO。例如,如果函数有多个return语句返回不同名称的对象,这样就不会执行RVO。如果想使用RVO,就必须返回相同名称的对象。

当编译器无法执行RVO时,可按计算性构造函数的形式来实现。

如果必须按值返回对象,通过RVO可以省去创建和销毁局部对象的步骤,从而改善性能。

RVO的应用要遵照编译器的实现而定。这需要参考编译器文档或通过实验来判断是否使用RVO以及何时使用。

通过编写计算性构造函数可以更好地使用RVO。

以下是测试代码(return_value_optimization.cpp):

#include "return_value_optimization.hpp"
#include <iostream>
#include <chrono>namespace return_value_optimization_ {// reference: 《提高C++性能的编程技术》:第四章:返回值优化class Complex {friend Complex operator + (const Complex&, const Complex&);friend void Complex_Add(const Complex&, const Complex&, Complex&);friend Complex Complex_Add2(const Complex&, const Complex&);friend Complex Complex_Add3(const Complex&, const Complex&);public:Complex(double r =0.0, double i =0.0) : real(r), imag(i) {} // 默认构造函数Complex(const Complex& c) : real(c.real), imag(c.imag) {} // 拷贝构造函数Complex(const Complex& a, const Complex& b) : real(a.real + b.real), imag(a.imag + b.imag) {} // 计算性构造函数Complex& operator = (const Complex& c) { this->real = c.real; this->imag = c.imag; return *this; }// 赋值运算符~Complex() {}private:double real;double imag;};Complex operator + (const Complex& a, const Complex& b)
{Complex retVal;retVal.real = a.real + b.real;retVal.imag = a.imag + b.imag;return retVal;
}// 消除局部对象retVal,直接把返回值放到__tempResult临时对象中来实现优化,这就是返回值优化(RVO)
void Complex_Add(const Complex& a, const Complex&b, Complex& __tempResult)
{__tempResult.real = a.real + b.real;__tempResult.imag = a.imag + b.imag;
}Complex Complex_Add2(const Complex& a, const Complex& b)
{Complex retVal;retVal.real = a.real + b.real;retVal.imag = a.imag + b.imag;return retVal;
}// 通过计算性构造函数来执行加操作
Complex Complex_Add3(const Complex& a, const Complex& b)
{return Complex(a, b);
}int test_return_value_optimization_1()
{// 测试两种加操作的实现性能:普通加操作、RVO加操作using namespace std::chrono;high_resolution_clock::time_point time_start, time_end;const int cycle_number {100000000};{ // 普通加操作Complex a(1, 0);Complex b(2, 0);Complex c;time_start = high_resolution_clock::now();for (int i = 0; i < cycle_number; ++i) {c = a + b;}time_end = high_resolution_clock::now();std::cout<<"common add time spent: "<<(duration_cast<duration<double>>(time_end - time_start)).count()<<" seconds\n";
}{ // RVO加操作Complex a(1, 0);Complex b(2, 0);Complex c;time_start = high_resolution_clock::now();for (int i = 0; i < cycle_number; ++i) {Complex_Add(a, b, c);}time_end = high_resolution_clock::now();std::cout<<"RVO add time spent: "<<(duration_cast<duration<double>>(time_end - time_start)).count()<<" seconds\n";
}// 测试两种加操作的实现性能:普通加操作、使用计算性构造函数{ // 普通加操作Complex a(1, 0);Complex b(2, 0);Complex c;time_start = high_resolution_clock::now();for (int i = 0; i < cycle_number; ++i) {c = Complex_Add2(a, b);}time_end = high_resolution_clock::now();std::cout<<"common add time spent: "<<(duration_cast<duration<double>>(time_end - time_start)).count()<<" seconds\n";
}{ // 使用计算性构造函数Complex a(1, 0);Complex b(2, 0);Complex c;time_start = high_resolution_clock::now();for (int i = 0; i < cycle_number; ++i) {c = Complex_Add3(a, b);}time_end = high_resolution_clock::now();std::cout<<"计算性构造函数 add time spent: "<<(duration_cast<duration<double>>(time_end - time_start)).count()<<" seconds\n";}return 0;
}} // namespace return_value_optimization_

运行结果如下:

GitHub: https://github.com/fengbingchun/Messy_Test

相关文章:

ICCV 2019 | 无需数据集的Student Networks

译者 | 李杰 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;本文是华为诺亚方舟实验室联合北京大学和悉尼大学在ICCV2019的工作。摘要在计算机视觉任务中&#xff0c;为了将预训练的深度神经网络模型应用到各种移动设备上&#xff0c;学习一个轻便的网络越来越重要。…

oc中特殊字符的判断方法

-(BOOL)isSpacesExists { // NSString *_string [NSString stringWithFormat:"123 456"]; NSRange _range [self rangeOfString:" "]; if (_range.location ! NSNotFound) { //有空格 return YES; }else { //没有空格 return NO; } } -(BOOL)i…

理解 Delphi 的类(十) - 深入方法[23] - 重载

为什么80%的码农都做不了架构师&#xff1f;>>> {下面的函数重名, 但参数不一样, 此类情况必须加 overload 指示字;调用时, 会根据参数的类型和个数来决定调用哪一个;这就是重载. }function MyFun(s: string): string; overload; beginResult : 参数是一个字符串: …

玩转ios友盟远程推送,16年5月图文防坑版

最近有个程序员妹子在做远程推送的时候遇到了困难&#xff0c;求助本帅。尽管本帅也是多彩的绘图工具&#xff0c;从没做过远程推送&#xff0c;但是本着互相帮助&#xff0c;共同进步的原则&#xff0c;本帅还是掩饰了自己的彩笔身份&#xff0c;耗时三天&#xff08;休息时间…

提高C++性能的编程技术笔记:临时对象+测试代码

类型不匹配&#xff1a;一般情况是指当需要X类型的对象时提供的却是其它类型的对象。编译器需要以某种方式将提供的类型转换成要求的X类型。这一过程可能会产生临时对象。 按值传递&#xff1a;创建和销毁临时对象的代价是比较高的。倘若可以&#xff0c;我们应该按指针或者引…

北美欧洲顶级大咖齐聚,在这里读懂 AIoT 未来!

2019 嵌入式智能国际大会即将来袭&#xff01;购票官网&#xff1a;https://dwz.cn/z1jHouwE随着海量移动设备的时代到来&#xff0c;以传统数据中心运行的人工智能计算正在受到前所未有的挑战。在这一背景下&#xff0c;聚焦于在远离数据中心的互联网边缘进行人工智能运算的「…

c# 关闭软件 进程 杀死进程

c# 关闭软件 进程 杀死进程 foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcessesByName("Server")){p.Kill();} 转载于:https://www.cnblogs.com/lxctboy/p/3999053.html

提高C++性能的编程技术笔记:单线程内存池+测试代码

频繁地分配和回收内存会严重地降低程序的性能。性能降低的原因在于默认的内存管理是通用的。应用程序可能会以某种特定的方式使用内存&#xff0c;并且为不需要的功能付出性能上的代价。通过开发专用的内存管理器可以解决这个问题。对专用内存管理器的设计可以从多个角度考虑。…

【Swift】 GETPOST请求 网络缓存的简单处理

GET & POST 的对比 源码&#xff1a; https://github.com/SpongeBob-GitHub/Get-Post.git 1. URL - GET 所有的参数都包含在 URL 中 1. 如果需要添加参数&#xff0c;脚本后面使用 ? 2. 参数格式&#xff1a;值对 参数名值 3. 如果有多个参数&#xff0c;使用 & 连接 …

深度CTR预估模型的演化之路2019最新进展

作者 | 锅逗逗来源 | 深度传送门&#xff08;ID: deep_deliver&#xff09;导读&#xff1a;本文主要介绍深度CTR经典预估模型的演化之路以及在2019工业界的最新进展。介绍在计算广告和推荐系统中&#xff0c;点击率&#xff08;Click Through Rate&#xff0c;以下简称CTR&…

2015大型互联网公司校招都开始了,薪资你准备好了嘛?

2015年的校招早就开始了&#xff0c;你还不知道吧&#xff1f;2015年最难就业季来了&#xff0c;你还没准备好嘛&#xff1f;现在就开始吧&#xff0c;已经很多大型互联网公司祭出毕业生底薪了看谷歌、看百度、看腾讯、看阿里巴巴再看传统软件公司&#xff1a;看微软、看联想、…

提高C++性能的编程技术笔记:多线程内存池+测试代码

为了使多个线程并发地分配和释放内存&#xff0c;必须在分配器方法中添加互斥锁。 全局内存管理器(通过new()和delete()实现)是通用的&#xff0c;因此它的开销也非常大。 因为单线程内存管理器要比多线程内存管理器快的多&#xff0c;所以如果要分配的大多数内存块限于单线程…

iOS中几种定时器

一、NSTimer 1. 创建方法 NSTimer *timer [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:selector(action:) userInfo:nil repeats:NO];TimerInterval : 执行之前等待的时间。比如设置成1.0&#xff0c;就代表1秒后执行方法target : 需要执行方法的对象…

手把手教你使用Flask轻松部署机器学习模型(附代码链接) | CSDN博文精选

作者 | Abhinav Sagar翻译 | 申利彬校对 | 吴金笛来源 | 数据派THU&#xff08;ID&#xff1a;DatapiTHU&#xff09;本文旨在让您把训练好的机器学习模型通过Flask API 投入到生产环境 。当数据科学或者机器学习工程师使用Scikit-learn、Tensorflow、Keras 、PyTorch等框架部署…

JQuery遮罩层

2019独角兽企业重金招聘Python工程师标准>>> css样式&#xff1a;<style type"text/css"> .mask { position: absolute; top: 0px; filter: alpha(opacity60); background-color: #777; z-index: 1002; left: 0px; …

代码覆盖测试工具Kcov简介及使用

Kcov是一个代码覆盖测试工具&#xff0c;最初基于Bcov&#xff0c;它可在FreeBSD、Linux、OSX系统中使用&#xff0c;支持的语言包括编译语言(compiled languages)、Python和Bash。与Bcov一样&#xff0c;Kcov对编译的程序使用DWARF调试信息&#xff0c;以便无需特殊编译器开关…

Google148亿元收购Fitbit,抢占苹果、三星可穿戴设备市场地盘

编译 | 夕颜出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;11 月 1 日&#xff0c;Google 母公司 Alphabet 和 可穿戴设备公司 Fitbit 同时发布新闻&#xff0c;宣布已经达成了收购后者的最终协议。Google LLC 以每股 7.35 美元的价格收购 Fitbit&#xff0c;总价值…

ios关于用xib创建的cell 自动返回cell的高度问题!

1 设置tableView的属性 self.tableView.rowHeight UITableViewAutomaticDimension; self.tableView.estimatedRowHeight 44.0; // 设置为一个接近“平均”行高的值 2 cell要约束好&#xff0c;要能够让cell知道自己的高度根据哪个控件计算就可以&#xff08;不明白看下图&…

西门子PLC学习笔记二-(工作记录)

今天师傅给讲了讲做自己主动化控制的总体的思路&#xff0c;特进行一下记录&#xff0c;做个备忘。 1.需求分析 本次的项目是对楼宇循环供水的控制&#xff0c;整个项目须要完毕压力、压差、温度等的获取及显示、同一时候完毕电机的控制。 2.设计 使用西门子的Step7工具进行梯形…

Swift 3.0 预告:将 Objc 库转换成更符合 Swift 语法风格的形式

转自&#xff1a;swiftcafe Swift 3.0 更新越来越临近&#xff0c;这次更新会给我们带来很多实用的内容&#xff0c;比如对 Objc 库的迁移&#xff0c;会更符合 Swift 的语法风格。用过之前版本的 Swift&#xff0c;我们会发现很多 Objc 库的方法名称其实还是以 Objc 的风格来命…

非对称加密算法RSA公钥私钥的模数和指数提取方法

生成非对称加密算法RSA公钥、私钥的方法&#xff1a; 1. 通过OpenSSL库生成&#xff0c;可参考 https://github.com/fengbingchun/OpenSSL_Test/blob/master/demo/OpenSSL_Test/funset.cpp 中的Generate_RSA_Key函数&#xff1b; 2. 在Linux下通过命令生成&#xff0c;执行…

数据库“新解”,看这里,get!

自从第一台通用计算机诞生至今&#xff0c;围绕计算机系统硬件的创新迭代就一直“在路上”&#xff0c;伴随着硬件能力的不断提升&#xff0c;软件更新自然不可缺少。通常来说在传统的计算机软件工程领域&#xff0c;操作系统、编译器与数据库被并称为最具难度的“三剑客”系统…

win 64位系统安装带有c编写的python模块出现ValueError: [u'path']解决

2019独角兽企业重金招聘Python工程师标准>>> 关于win 64位机器安装Scrapy的问题&#xff1a;http://steamforge.net/wiki/index.php/How_to_Install_Scrapy_in_64-bit_Windows_7 在安装Scrapy是要安装一系列的依赖模块&#xff0c; 出现问题&#xff1a; 1、error: …

探索 Swift 中的 MVC-N 模式

作者&#xff1a;Marcus Zarra&#xff08;twitter&#xff1a;mzarra&#xff09; Marcus 将会为大家介绍一种设计模式&#xff0c;他曾经在那些需要从互联网进行大量频繁数据请求的 iOS 应用当中使用此设计模式。这个设计采用了著名的 MVC (Model View Controller) 模式&…

MXNet中依赖库介绍及简单使用

MXNet是一种开源的深度学习框架&#xff0c;核心代码是由C实现&#xff0c;在编译源码的过程中&#xff0c;它需要依赖其它几种开源库&#xff0c;这里对MXNet依赖的开源库进行简单的说明&#xff1a; 1. OpenBLAS&#xff1a;全称为Open Basic Linear Algebra Subprograms&am…

Python十大装腔语法

作者 | 许向武 责编 | 郭芮 来源 | CSDN 博客Python 是一种代表简单思想的语言&#xff0c;其语法相对简单&#xff0c;很容易上手。不过&#xff0c;如果就此小视 Python 语法的精妙和深邃&#xff0c;那就大错特错了。本文精心筛选了最能展现 Python 语法之精妙的十个知识点&…

MATLAB——scatter的简单应用

scatter可用于描绘散点图。 1.scatter(X,Y) X和Y是数据向量&#xff0c;以X中数据为横坐标&#xff0c;以Y中数据位纵坐标描绘散点图&#xff0c;点的形状默认使用圈。 样例&#xff1a; X [1:10]; Y X rand(size(X)); scatter(X, Y) 得到&#xff1a; 2.scatter(...,fill…

Windows10上使用VS2017编译MXNet源码操作步骤(C++)

MXNet是一种开源的深度学习框架&#xff0c;核心代码是由C实现。MXNet官网推荐使用VS2015或VS2017编译&#xff0c;因为源码中使用了一些C14的特性&#xff0c;VS2013是不支持的。这里通过VS2017编译&#xff0c;步骤如下&#xff1a; 1. 编译OpenCV&#xff0c;版本为3.4.2&a…

StoryBoard 视图切换和传值

一 于StoryBoard相关的类、方法和属性 1 UIStoryboard // 根据StoryBoard名字获取StoryBoard (UIStoryboard *)storyboardWithName:(NSString *)name bundle:(nullable NSBundle *)storyboardBundleOrNil;// 获取指定StoryBoard的第一个视图控制器- (nullable __kindof UIViewC…

率清华团队研发“天机芯”登《Nature》封面,他说类脑计算是发展人工通用智能的基石...

整理 | AI科技大本营&#xff08;ID:rgznai100&#xff09;8 月&#xff0c;清华大学教授、类脑计算研究中心主任施路平率队研发的关于“天机芯”的论文登上《Nature》封面&#xff0c;这实现了中国在芯片和人工智能两大领域登上该杂志论文零的突破&#xff0c;引发国内外业界一…