虚函数:在以下几个方面,虚函数可能会造成性能损失:构造函数必须初始化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

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

  1. 提高C++性能的编程技术笔记:总结

    <提高C++性能的编程技术>这本书是2011年出版的,书中有些内容的介绍可能已经过时,已不再适用于现在的C++编程中,但大部分内容还是很有参考意义的. 这里是基于之前所有笔记的简单总结,笔 ...

  2. 提高C++性能的编程技术笔记:内联+测试代码

    内联类似于宏,在调用方法内部展开被调用方法,以此来代替方法的调用.一般来说表达内联意图的方式有两种:一种是在定义方法时添加内联保留字的前缀:另一种是在类的头部声明中定义方法. 虽然内联方法的调用方式和 ...

  3. 提高C++性能的编程技术笔记:设计优化/可扩展性/系统体系结构相关+测试代码

    1. 设计优化 我们可以粗略地将性能优化分为两种类型:编码优化和设计优化.编码优化定义为不需要完整理解要解决的问题或者应用程序的执行流程就能实施的优化.通过定义看出,编码优化用于局部代码,同时该过程不 ...

  4. 提高C++性能的编程技术笔记:编码优化+测试代码

    缓存:在现代处理器中,缓存经常与处理器中的数据缓存和指令缓存联系在一起.缓存主要用来存储使用频繁而且代价高昂的计算结果,这样就可以避免对这些结果的重复计算.如,循环内对常量表达式求值是一种常见的低性能 ...

  5. 提高C++性能的编程技术笔记:引用计数+测试代码

    引用计数(reference counting):基本思想是将销毁对象的职责从客户端代码转移到对象本身.对象跟踪记录自身当前被引用的数目,在引用计数达到零时自行销毁.换句话说,对象不再被使用时自行销毁 ...

  6. 提高C++性能的编程技术笔记:标准模板库+测试代码

    标准模板库(Standard Template Library, STL)是容器和通用算法的强效组合. 渐近复杂度:算法的渐近复杂度是对算法性能的近似估计.它是算法集到特定性能标准集的映射.如果需要对 ...

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

    为了使多个线程并发地分配和释放内存,必须在分配器方法中添加互斥锁. 全局内存管理器(通过new()和delete()实现)是通用的,因此它的开销也非常大. 因为单线程内存管理器要比多线程内存管理器快的 ...

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

    频繁地分配和回收内存会严重地降低程序的性能.性能降低的原因在于默认的内存管理是通用的.应用程序可能会以某种特定的方式使用内存,并且为不需要的功能付出性能上的代价.通过开发专用的内存管理器可以解决这个问 ...

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

    类型不匹配:一般情况是指当需要X类型的对象时提供的却是其它类型的对象.编译器需要以某种方式将提供的类型转换成要求的X类型.这一过程可能会产生临时对象. 按值传递:创建和销毁临时对象的代价是比较高的.倘 ...

最新文章

  1. 机器学习(10)随机森林(预测泰坦尼克号旅客存活率)
  2. 程序员敲诈老板,或面临 37 年监禁
  3. Web3DGame之路,Babylonjs 和TypeScript学习笔记(二)
  4. 【opencv】15.H265Decoder解码h265为cv::Mat完整代码
  5. Unity3D去掉全屏时的屏幕黑边
  6. Django 权限管理
  7. package.json和package-lock.json
  8. NAS 百科 —— http://baike.baidu.com/item/NAS%E7%BD%91%E7%BB%9C%E5%AD%98%E5%82%A8
  9. 让多核CPU占用率曲线听你指挥(Windows实现)——《编程之美》1.1学习笔记
  10. 双系统下修复grub
  11. 数说海南——简单分析海南各市县近六年人口吸引力情况
  12. 教育教学教师竞聘说课PPT模板
  13. fastboot 常用命令
  14. 怎么在Excel中快速将英文翻译为中文
  15. 新浪微博注册页面的用户体验分析报告(转载)
  16. 读懂西瓜书 14 : 概率图模型
  17. 四层负载均衡,请别再浑水摸鱼了! 太一星晨解析七层负载均衡关键技术
  18. 应用内moniter
  19. 新闻推荐系统:深度知识感知网络DKN
  20. Python 蓝桥杯试题 基础练习 数列排序

热门文章

  1. Linux那些事儿 之 戏说USB(20)设备的生命线(三)
  2. OpenCV(25)轮廓检测(轮廓提取、属性、近似轮廓、外接矩形和外接圆)
  3. Open3d学习计划—高级篇 5(RGBD融合)
  4. Open3d学习计划—高级篇 2(彩色点云配准)
  5. Ubuntu 16.04.1 LTS上安装电源管理系统TLP
  6. C++中stl使用过程中的一些tips
  7. Ubuntu 14.04 64bit上解析wireshark抓包pcap文件格式和源码实现
  8. Python入门基础教程 Working with Python – Introductory Level
  9. 在UE5创造一个多山的松树森林场景学习教程
  10. 一篇文章让你搞懂原型和原型链