提高C++性能的编程技术笔记:构造函数和析构函数+测试代码
对象的创建和销毁往往会造成性能的损失。在继承层次中,对象的创建将引起其先辈的创建。对象的销毁也是如此。其次,对象相关的开销与对象本身的派生链的长度和复杂性相关。所创建的对象(以及其后销毁的对象)的数量与派生的复杂度成正比。
并不是说继承根本上就是代码性能的绊脚石。我们必须区分全部计算开销、必须开销和计算损失(computional penalty). 全部计算开销是一次计算中所执行的全部指令的总和。必须开销是全部指令的子集,它的结果是必要的。这部分计算是必需的,其余部分即为计算损失。计算损失是可以通过别的设计和实现来消除的那部分计算。
我们不能断言采用了复杂的继承的设计一定是坏的,也不能断定它们总是带来性能损失。我们只能说总的开销会随着派生树规模的增长而增加。如果所有的计算都是有价值的,那么它们都是必须的开销。实际上,继承层次不见得是完善的,在这种情况下,它们很可能会导致计算损失。
对象的复合与继承一样,都引入了与对象创建和销毁有关的类似性能问题。在对象被创建(或销毁)时,必须同时创建(或销毁)它所包含的成员对象。
创建和销毁被包含对象是另一个值得注意的问题:在创建(或销毁)被包含对象时无法阻止子对象的创建(或销毁),因为这是编译器自动强加的步骤。
性能优化经常需要牺牲一些其它软件目标,诸如灵活性、可维护性、成本和重用之类的重要目标经常必须为性能让步。
在C++中,不自觉地在程序开始处预先定义所有对象的做法是一种浪费。因为这样可能会创建一些直到最后都没有用到的对象。在C++中,把变量的创建延迟到第一次使用前。
构造函数和析构函数可以像手工编写的C代码一样有效。然而在实践中,它们经常包含冗余计算。
对象的创建(或销毁)触发对父对象和成员对象的递归创建(或销毁)。
要确保所编写的代码实际使用了所有创建的对象和这些对象所执行的计算。
对象的生命周期不是无偿的。至少对象的创建和销毁会消耗CPU周期。不要随意创建一个对象,除非你打算使用它。通常情况下,要等到需要使用对象的地方再创建它。
编译器必须初始化被包含的成员对象之后再执行构造函数体。你必须在初始化阶段完成成员对象的创建。这可以降低随后在构造函数部分调用赋值操作符的开销。在某些情况下,这样也可以避免临时对象的产生。
以下是测试代码(constructors_and_destructors.cpp):
#include "constructors_and_destructors.hpp"
#include <iostream>
#include <string>
#include <mutex>
#include <chrono>namespace constructors_destructors_ {// reference: 《提高C++性能的编程技术》:第二章:构造函数和析构函数class SimpleMutex { // 单独的锁类
public:SimpleMutex(std::mutex& mtx) : mymtx(mtx) { acquire(); }~SimpleMutex() { release(); }private:void acquire() { mymtx.lock(); }void release() { mymtx.unlock(); }std::mutex& mymtx;
};class BaseMutex { // 基类
public:BaseMutex(std::mutex& mtx) {}virtual ~BaseMutex() {}
};class DerivedMutex : public BaseMutex {
public:DerivedMutex(std::mutex& mtx) : BaseMutex(mtx), mymtx(mtx) { acquire(); }~DerivedMutex() { release(); }private:void acquire() { mymtx.lock(); }void release() { mymtx.unlock(); }std::mutex& mymtx;};class Person1 {
public:Person1(const char* s) { name = s; } // 隐式初始化和显示赋值private:std::string name;
};class Person2 {
public:Person2(const char* s) : name(s) {} // 显示初始化private:std::string name;
};int test_constructors_destructors_1()
{// 测试三种互斥锁的实现// Note:与书中实验结果有差异,在这里继承对象并不会占用较多的执行时间,在这里这三种所占用时间基本差不多using namespace std::chrono;high_resolution_clock::time_point time_start, time_end;const int cycle_number {100000000};int shared_counter {0};{ // 1.直接调用mutexstd::mutex mtx;shared_counter = 0;time_start = high_resolution_clock::now();for (int i = 0; i < cycle_number; ++i) {mtx.lock();++shared_counter;mtx.unlock();}time_end = high_resolution_clock::now();std::cout<< "time spen1: "<<(duration_cast<duration<double>>(time_end - time_start)).count()<< " seconds\n";
}{ // 2.不从基类继承的独立互斥对象std::mutex mtx;shared_counter = 0;time_start = high_resolution_clock::now();for (int i = 0; i < cycle_number; ++i) {SimpleMutex m(mtx);++shared_counter;}time_end = high_resolution_clock::now();std::cout<< "time spen2: "<<(duration_cast<duration<double>>(time_end - time_start)).count()<<" seconds\n";
}{ // 3.从基类派生的互斥对象std::mutex mtx;shared_counter = 0;time_start = high_resolution_clock::now();for (int i = 0; i < cycle_number; ++i) {DerivedMutex m(mtx);++shared_counter;}time_end = high_resolution_clock::now();std::cout<< "time spen3: "<<(duration_cast<duration<double>>(time_end - time_start)).count()<<" seconds\n";}// 隐式初始化和显示赋值与显示初始化性能对比:使用显示初始化操作要优于使用隐式初始化和显示赋值操作
{ // 1.隐式初始化和显示赋值操作time_start = high_resolution_clock::now();for (int i = 0; i < cycle_number; ++i) {Person1 p("Pele"); }time_end = high_resolution_clock::now();std::cout<< "隐式初始化, time spen: "<<(duration_cast<duration<double>>(time_end - time_start)).count()<<" seconds\n";
}{ // 2.显示初始化操作time_start = high_resolution_clock::now();for (int i = 0; i < cycle_number; ++i) {Person2 p("Pele");}time_end = high_resolution_clock::now();std::cout<<"显示初始化, time spen: "<<(duration_cast<duration<double>>(time_end - time_start)).count()<<" seconds\n";
}return 0;
}} // namespace constructors_destructors_
运行结果如下:
GitHub: https://github.com/fengbingchun/Messy_Test
相关文章:

swim 中一行代码解决收回键盘
//点击空白收回键盘 override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { view.endEditing(true) }

WinAPI: SetRect 及初始化矩形的几种办法
为什么80%的码农都做不了架构师?>>> 本例分别用五种办法初始化了同样的一个矩形, 运行效果图: unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls;typeTForm1 class(TForm)Butto…

Windows10上使用VS2017编译OpenCV3.4.2+OpenCV_Contrib3.4.2+Python3.6.2操作步骤
1. 从https://github.com/opencv/opencv/releases 下载opencv-3.4.2.zip并解压缩到D:\soft\OpenCV3.4.2\opencv-3.4.2目录下; 2. 从https://github.com/opencv/opencv_contrib/releases 下载opencv_contrib-3.4.zip并解压缩到D:\soft\OpenCV3.4.2\opencv_contrib-3…

swift 跳转网页写法
var alert : UIAlertView UIAlertView.init(title: "公安出入境网上办事平台", message: "目前您可以使用网页版进行出入境业务预约与查询,是否进入公安出入境办事平台?", delegate: nil, cancelButtonTitle: "取消", o…

智能边缘计算:计算模式的再次轮回
作者 | 刘云新来源 | 微软研究院AI头条(ID:MSRAsia)【导读】人工智能的蓬勃发展离不开云计算所带来的强大算力,然而随着物联网以及硬件的快速发展,边缘计算正受到越来越多的关注。未来,智能边缘计算将与智能云计算互为…

WinAPI: 钩子回调函数之 SysMsgFilterProc
为什么80%的码农都做不了架构师?>>> SysMsgFilterProc(nCode: Integer; {}wParam: WPARAM; {}lParam: LPARAM {} ): LRESULT; {}//待续...转载于:https://my.oschina.net/hermer/blog/319736

提高C++性能的编程技术笔记:虚函数、返回值优化+测试代码
虚函数:在以下几个方面,虚函数可能会造成性能损失:构造函数必须初始化vptr(虚函数表);虚函数是通过指针间接调用的,所以必须先得到指向虚函数表的指针,然后再获得正确的函数偏移量;内联是在编译…

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

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

玩转ios友盟远程推送,16年5月图文防坑版
最近有个程序员妹子在做远程推送的时候遇到了困难,求助本帅。尽管本帅也是多彩的绘图工具,从没做过远程推送,但是本着互相帮助,共同进步的原则,本帅还是掩饰了自己的彩笔身份,耗时三天(休息时间…

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

北美欧洲顶级大咖齐聚,在这里读懂 AIoT 未来!
2019 嵌入式智能国际大会即将来袭!购票官网:https://dwz.cn/z1jHouwE随着海量移动设备的时代到来,以传统数据中心运行的人工智能计算正在受到前所未有的挑战。在这一背景下,聚焦于在远离数据中心的互联网边缘进行人工智能运算的「…

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

提高C++性能的编程技术笔记:单线程内存池+测试代码
频繁地分配和回收内存会严重地降低程序的性能。性能降低的原因在于默认的内存管理是通用的。应用程序可能会以某种特定的方式使用内存,并且为不需要的功能付出性能上的代价。通过开发专用的内存管理器可以解决这个问题。对专用内存管理器的设计可以从多个角度考虑。…

【Swift】 GETPOST请求 网络缓存的简单处理
GET & POST 的对比 源码: https://github.com/SpongeBob-GitHub/Get-Post.git 1. URL - GET 所有的参数都包含在 URL 中 1. 如果需要添加参数,脚本后面使用 ? 2. 参数格式:值对 参数名值 3. 如果有多个参数,使用 & 连接 …

深度CTR预估模型的演化之路2019最新进展
作者 | 锅逗逗来源 | 深度传送门(ID: deep_deliver)导读:本文主要介绍深度CTR经典预估模型的演化之路以及在2019工业界的最新进展。介绍在计算广告和推荐系统中,点击率(Click Through Rate,以下简称CTR&…
2015大型互联网公司校招都开始了,薪资你准备好了嘛?
2015年的校招早就开始了,你还不知道吧?2015年最难就业季来了,你还没准备好嘛?现在就开始吧,已经很多大型互联网公司祭出毕业生底薪了看谷歌、看百度、看腾讯、看阿里巴巴再看传统软件公司:看微软、看联想、…

提高C++性能的编程技术笔记:多线程内存池+测试代码
为了使多个线程并发地分配和释放内存,必须在分配器方法中添加互斥锁。 全局内存管理器(通过new()和delete()实现)是通用的,因此它的开销也非常大。 因为单线程内存管理器要比多线程内存管理器快的多,所以如果要分配的大多数内存块限于单线程…

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

手把手教你使用Flask轻松部署机器学习模型(附代码链接) | CSDN博文精选
作者 | Abhinav Sagar翻译 | 申利彬校对 | 吴金笛来源 | 数据派THU(ID:DatapiTHU)本文旨在让您把训练好的机器学习模型通过Flask API 投入到生产环境 。当数据科学或者机器学习工程师使用Scikit-learn、Tensorflow、Keras 、PyTorch等框架部署…

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

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

Google148亿元收购Fitbit,抢占苹果、三星可穿戴设备市场地盘
编译 | 夕颜出品 | AI科技大本营(ID:rgznai100)11 月 1 日,Google 母公司 Alphabet 和 可穿戴设备公司 Fitbit 同时发布新闻,宣布已经达成了收购后者的最终协议。Google LLC 以每股 7.35 美元的价格收购 Fitbit,总价值…

ios关于用xib创建的cell 自动返回cell的高度问题!
1 设置tableView的属性 self.tableView.rowHeight UITableViewAutomaticDimension; self.tableView.estimatedRowHeight 44.0; // 设置为一个接近“平均”行高的值 2 cell要约束好,要能够让cell知道自己的高度根据哪个控件计算就可以(不明白看下图&…
西门子PLC学习笔记二-(工作记录)
今天师傅给讲了讲做自己主动化控制的总体的思路,特进行一下记录,做个备忘。 1.需求分析 本次的项目是对楼宇循环供水的控制,整个项目须要完毕压力、压差、温度等的获取及显示、同一时候完毕电机的控制。 2.设计 使用西门子的Step7工具进行梯形…

Swift 3.0 预告:将 Objc 库转换成更符合 Swift 语法风格的形式
转自:swiftcafe Swift 3.0 更新越来越临近,这次更新会给我们带来很多实用的内容,比如对 Objc 库的迁移,会更符合 Swift 的语法风格。用过之前版本的 Swift,我们会发现很多 Objc 库的方法名称其实还是以 Objc 的风格来命…

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

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

win 64位系统安装带有c编写的python模块出现ValueError: [u'path']解决
2019独角兽企业重金招聘Python工程师标准>>> 关于win 64位机器安装Scrapy的问题:http://steamforge.net/wiki/index.php/How_to_Install_Scrapy_in_64-bit_Windows_7 在安装Scrapy是要安装一系列的依赖模块, 出现问题: 1、error: …