c++
^Moon^
这个作者很懒,什么都没留下…
展开
-
C++11特性-委派构造函数-的益处
对于复杂的C++类,有很多个构造函数是非常常见的。为了减少重复代码,经常看到在一个构造函数里调用另一个构造函数的情况。#include <iostream>using namespace std;class Info{public: Info() { Init(); printInfo();}; Info(int i) { Info(); type = i; printInfo();} Info(char e) { name = e; Info(); print原创 2021-11-02 14:51:27 · 379 阅读 · 0 评论 -
C++性能优化笔记-16-嵌入式系统中的优化
嵌入式系统中的优化小型嵌入式应用中使用的微控制器的计算资源少于标准PC。时钟频率可能比标准PC低一百倍甚至一千倍;内存量甚至可能比PC机少一百万倍。然而,如果您避免大型图形框架、解释器、即时编译器、系统数据库和其他通常在大型系统上使用的额外软件层和框架,就有可能使软件在如此小的设备上运行得相当快。系统越小,选择使用很少资源的软件框架就越重要。在最小的设备上,您甚至没有操作系统。最好的性能是通过选择一种可以在PC机上交叉编译的编程语言,然后把机器代码传输到设备上。任何需要在设备上编译或解释的语言都是对资翻译 2021-09-27 19:43:06 · 266 阅读 · 0 评论 -
C++性能优化笔记-15-测试执行速度
测试执行速度使用性能监视器计数单元测试的陷阱最坏情况测试测试程序的速度是优化工作的一个重要部分。你必须检查你的修改是否确实提高了速度。有各种各样的分析器可用于查找热点和测量程序的总体性能。然而,分析器并不总是准确的,当程序花费大部分时间等待用户输入或读取磁盘文件时,可能很难准确测量您想要的内容。有关分析的讨论,请参见执行时间分析。确定热点后,隔离热点并仅对代码的这一部分进行测量可能很有用。这可以通过使用所谓的时间戳计数器获取CPU时钟周期来完成。这是一个计数器,用于测量CPU启动后的时钟脉冲数。时钟周原创 2021-09-27 19:00:32 · 896 阅读 · 0 评论 -
C++性能优化笔记-14-元编程
元编程模板元编程编译期常量分支元编程编译期常量函数元编程元编程意味着开发可以生成代码的代码。例如,在解释型脚本语言中,通常可以开发一段生成字符串的代码,然后将此字符串解释为代码。元编程在编译型语言如C++中有帮助。如果计算所需的所有输入在编译时可知,则可以在编译时而不是在运行时进行计算。当然,在解释型语言中没有这样的优势,因为一切都在运行时发生。以下技术可以视为C++中的元编程:预处理器指令。例如,使用#if而不是if。这是一个非常有用的删除多余代码的方法,但有严重的限制,预处理器位于编译器之前,原创 2021-09-27 16:54:02 · 583 阅读 · 0 评论 -
C++性能优化笔记-13-特定优化主题
特定优化主题使用查找表边界检查使用位操作符一次检测多个值整数乘法整数除法浮点除法不要混合使用浮点和双精度浮点数和整数的转换在浮点变量乘法中使用整数操作数学函数静态库VS动态库位置无关代码系统编程使用查找表如果缓存了常数表,则从该表读取值的速度非常快。通常,从一级cache中的表读取值只需要几个时钟周期。利用这一事实,如果函数只有有限数量的输入,我们可以通过用表查找来替换函数调用。让我们以整数阶乘函数(n!)为例。唯一允许的输入是0到12之间的整数。高输入产生溢出,负输入产生无穷大。阶乘函数的典型实现如原创 2021-09-26 20:58:24 · 429 阅读 · 0 评论 -
C++性能优化笔记-12-开发兼容多个指令集的关键代码
开发兼容多个指令集的关键代码CPU调度策略模型相关调度不同场景测试和维护实现Linux中加载阶段的CPU调度Intel编译器中的CPU调度微处理器制造商会不断添加新指令到指令集中,从而让直行速度更快。使用新指令集的坏处是和旧型号的微处理器不兼容。这个困境可以通过让代码的关键部分兼容多个版本的指令集来解决。这叫CPU调度。应用程序应该自动侦测CPU和操作系统支持哪个指令集,进而选择为最内层的关键循环选择合适的子程序版本。CPU调度策略开发一段支持多指令集的代码代价是高昂的-在开发、测试和维护方面。把这些原创 2021-09-24 15:21:37 · 885 阅读 · 0 评论 -
C++性能优化笔记-11-使用向量操作
使用向量操作AVX指令集和YMM寄存器AVX512指令集和ZMM寄存器自动向量化使用内建函数对齐数据向量化表查找使用向量类向量类的CPU分发转换串行代码到向量化代码数学函数的向量化对齐动态分配的内存对齐RGB视频或三维向量结论今天的微处理器有向量指令,这让在一个向量的所有元素上进行操作成为可能。这样叫单指令多数据(SIMD)操作。每个向量的大小可以是64位(MMX),128位(XMM),256位(YMM)和512位(ZMM)。当需要在大数据集上,对多个数据执行相同的操作,并且程序逻辑也允许时,向量操作是原创 2021-09-22 19:31:50 · 3618 阅读 · 0 评论 -
C++性能优化笔记-10-无序执行
无序执行无序执行无序执行所有现代的X86处理器都可以无序执行指令。下边的例子利用了这个能力:// Example 11.1afloat a, b, c, d, y;y = a + b + c + d;这个表达式按照((a+b)+c)+d)计算。这是一个依赖链。可以进行修改改善:// Example 11.1bfloat a, b, c, d, y;y = (a + b) + (c + d);现在(a+b)和(c+d)可以同时进行,可以节约几个时钟周期。不能假定编译器会自动进行上述优化原创 2021-09-22 10:44:50 · 195 阅读 · 0 评论 -
C++性能优化笔记-9-多线程
多线程线程同步CPU时钟频率限制于物理硬件因素。在时钟频率的限制下,提高CPU密集型程序吞吐量的方式是,同时进行多个任务。任务并行有三种方式:使用多个CPU或多核CPU;利用现在CPU的乱序能力;利用现代CPU的向量操作;为了利用CPU的多核能力,需要把问题拆分为多个线程。线程同步...原创 2021-09-18 14:38:25 · 1598 阅读 · 0 评论 -
expected unqualified-id before numeric constant
在编译开源的第三方库时,可能会遇到错误:expected unqualified-id before numeric constant分析后发现,是自己定义的枚举变量名与第三方库中的同名了,导致变量重复定义。解决方法:自己的类型加上命名空间自定义的类型添加特定的前缀...原创 2021-09-17 17:22:47 · 7418 阅读 · 0 评论 -
C++性能优化笔记-8-优化存储访问
优化存储访问优化存储访问代码和数据缓存缓存组织一起使用的函数应该存储在一起一起使用的变量应该存储在一起数据对齐动态内存分配数据结构和容器类字符串顺序访问数据大数据结构中的cache冲突显式cache控制优化存储访问代码和数据缓存缓存是主存的代理。缓存是为了以最快的可能访问最常用的数据。缓存组织大多数chache以行和集合的方式组织。cache机制的更多细节,参考(en.wikipedia.org/wiki/L2_cache)。如果程序中包含很多变量和对象,它们又刚好分布在映射到相同cache的内原创 2021-09-17 16:14:32 · 1177 阅读 · 0 评论 -
C++性能优化笔记-7-编译器中的优化-5-编译器做了什么
编译器中的优化检查编译器做了什么检查编译器做了什么研究编译器产生的代码,看它优化代码的程度,是非常有用的。有时,编译器会相当奇妙地使代码更高效,有时它蠢得难以置信。看编译器输出通常可以透露出什么可以通过修改源代码来改进,如下面例子所示。检查编译器产生代码最好的方式是使用汇编语言输出的编译器选项。在大多数编译器上,你可以通过从命令行使用相关优化选项,以及汇编输出的选项-S或/Fa,调用编译器来完成。在某些系统上,IDE也有可用的汇编输出选项。如果编译器没有汇编输出选项,使用目标文件反汇编器。注意,In原创 2021-09-13 17:01:16 · 297 阅读 · 0 评论 -
C++性能优化笔记-7-编译器中的优化-4-编译器优化选项、优化指令
编译器中的优化编译器优化选项优化指令编译器优化选项所有C++编译器有各种你可以打开、关闭的优化选项。学习正在使用编译器可用的选项,并打开所有相关选项,是重要的。许多优化选项与调试不兼容。调试器可以一次执行一行代码,并显示所有变量的值。显然,在部分代码被重排、内联或优化掉时,这是不可能的。通常制作可执行程序的两个版本:带有完整调试支持,在程序开发期间使用的调试版本,以及打开所有相关优化选项的发布版本。大多数IDE(集成开发环境)有制作目标文件与可执行文件的调试版本与发布版本的设施。确保区分这两个版本,在原创 2021-09-12 17:07:19 · 1683 阅读 · 0 评论 -
C++性能优化笔记-7-编译器中的优化-3-编译器、CPU优化的障碍
编译器中的优化编译器优化的障碍不能跨模块优化指针别名动态内存分配纯函数虚函数与函数指针代数化简浮点归纳变量具有非内联拷贝的内联函数CPU优化的障碍编译器优化的障碍有几个因素会阻止编译器进行预期的优化。程序员知道这些障碍并知道如何避免它们。优化的某些重要的障碍讨论如下。不能跨模块优化编译器没有除正在编译模块以外其他模块中的函数信息。这阻止了跨函数调用的优化。如:// Example 8.20**module1.cpp**int Func1(int x) { return x*x +原创 2021-09-12 14:30:18 · 737 阅读 · 0 评论 -
C++性能优化笔记-7-编译器中的优化-2-不同编译器的对比
编译器中的优化不同编译器的对比不同编译器的对比下表对比了不同的编译器的优化效果。必须强调的是,编译器在不同的测试例子上可能表现不同。下表仅供参考。优化方法GnuClangMicrosoftIntel通用优化函数内联xxxx常量折叠xxxx常量传播xxxx循环的常量传播xx--指针消除xxxx公共子表达式消除xxxx寄存器变量xxxxFused multiply a原创 2021-09-11 17:14:08 · 568 阅读 · 0 评论 -
C++性能优化笔记-7-编译器中的优化-1-编译器如何优化代码
编译器中的优化编译器如何优化函数内联常量折叠和常量传播指针消除公共子表达式消除寄存器变量生命周期分析合并相同的分支消除跳转循环展开循环不变代码移动归纳变量调度代数化简去虚拟化编译器如何优化现代编译器能够对代码做很多修改,以提高性能。了解编译器可以做什么,不可以做什么,对开发者来说是有用的。下边的小节描述了开发者需要了解的一些编译器优化的内容。函数内联编译器可以用被调用函数体来替换原来的函数调用。例子:// Example 8.1afloat square (float a) { re原创 2021-09-10 18:56:07 · 1389 阅读 · 1 评论 -
C++性能优化笔记-6-C++元素的效率差异-18-预处理和命名空间
C++元素的效率差异预处理指令命名空间预处理指令就程序性能而言,预处理指示(所有以#开头的东西)是没有代价的,因为它们在程序编译前被解决了。#if指令用于支持多平台或同一个源代码的多种配置。#if比if更高效,因为#if在编译时解析,而if在运行时。在用于定义常量时,#define等价于const定义。例如,#define ABC 123与const int ABC = 123;一样高效,因为在大多数情形里,优化的编译器会用值替换一个整数常量。不过,在某些情形里,const int声明需要内存空间,原创 2021-09-08 18:39:34 · 172 阅读 · 0 评论 -
C++性能优化笔记-6-C++元素的效率差异-17-栈展开、NAN和INF传播
C++元素的效率差异栈回滚的其他情形NAN和INF的传播栈回滚的其他情形前面的章节描述了由异常处理使用的、称为栈回滚的机制,在异常出现时,不使用正常返回途径跳出函数后,由异常处理用来清理及调用所有必须的析构函数。这个机制也用在其他两个情形里:在线程终止时,可以使用栈回滚机制。目的是检测线程中声明的对象是否有需要调用的析构函数。建议在终止线程前,从要求清理的函数返回。不能确定的,_endthread()的调用会清理栈。取决于实现。在使用函数longjmp跳出一个函数时,也使用栈回滚机制。尽可能避免使原创 2021-09-08 18:29:30 · 110 阅读 · 0 评论 -
C++性能优化笔记-6-C++元素的效率差异-16-异常和错误处理
C++元素的效率差异异常与错误处理异常与向量代码避免异常处理的代价开发异常安全代码异常与错误处理运行时错误已发异常,这些异常可以通过陷阱或软件中断的形式被检测到。这些异常可以通过 try-catch 块捕捉到。程序会崩溃并产生一个错误消息,如果异常处理被启用并且没有 try-catch 块。异常处理的目的是检测很少出现的错误,并以一个优雅的方式从错误中恢复。你可能认为只要错误不发生,异常处理就不需要额外时间,但不幸的是,这不总是成立的。程序必须进行许多簿记以便知道如何从异常事件中恢复。这个簿记的代价很原创 2021-09-08 16:52:57 · 231 阅读 · 0 评论 -
C++性能优化笔记-6-C++元素的效率差异-14-模板
C++元素的效率差异模板模板就在编译前模板参数被它们的值替代而言,模板类似于宏。下面的例子展示了函数参数与模板参数间的差别:// Example 7.46int Multiply (int x, int m) {return x * m;}template int MultiplyBy (int x) {return x * m;}int a, b;a = Multiply(10,8);b = MultiplyBy<8>(10);a与b都将给出值10 * 8 = 80。差原创 2021-09-07 20:22:50 · 632 阅读 · 0 评论 -
C++性能优化笔记-6-C++元素的效率差异-11-结构体和类
C++元素的效率差异结构体和类类数据成员类成员函数(方法)虚函数运行时类型识别(RTTI)继承构造函数与析构函数结构体和类时至今日,编程教材推荐面向对象编程,作为使软件更清晰及模块化的一种手段。所谓的对象是结构体及类的实例。面向对象编程形式对程序性能有积极与消极的影响。积极的影响有:一起使用的变量也保存在一起,如果它们是结构体或类的成员。这使得数据缓存更高效。作为类成员的变量无需作为参数传递给类成员函数。这些变量避免了参数传递的开销。消极影响有:一些程序员把代码分到太多的小的类中。这是低原创 2021-09-06 19:13:34 · 981 阅读 · 0 评论 -
C++性能优化笔记-6-C++元素的效率差异-7-类型转换
C++元素的效率差异类型转换signed与unsigned转换整数大小转换浮点精度转换整数到浮点转换浮点到整数转换指针类型转换重新解释对象的类型const_caststatic_castreinterpret_castdynamic_cast转换类对象类型转换在C++语法中,有几种方式进行类型转换:// Example 7.19int i; float f;f = i; // Implicit type conversionf = (float)i; // C-style t原创 2023-11-03 17:19:26 · 2063 阅读 · 1 评论 -
C++性能优化笔记-1-平台选择
一、硬件平台的选择随着硬件设计变化和性能的提升,硬件平台选择越来越不重要了。现在硬件平台的选择更多考虑的不是处理能力,而是价格、兼容性、可替代性、开发工具的可得性等。采用普通PC网络集群,往往比投资大型机更便宜和有效。超级计算机在科学计算领域仍然有优势。但是对于绝大多数普通任务,标准PC更具性价比。由于现在主流处理器已经是X64,CISC指令集寄存器太少的问题已经得到缓解。对于关键应用,不建议采用依赖网络资源的轻量客户端模式,原因是网络资源的响应时间无法控制。现在小型手持设备越来越多,其硬件资源比P原创 2021-08-23 17:20:40 · 517 阅读 · 0 评论 -
类库开发技巧-1
文章目录前言Bitflags使用d指针前言当开发类库时,最大的问题是不能安全地添加数据成员。因为这样做会改变包含被修改的类对象(包括子类)的所有类、结构体或数组的大小和布局。Bitflags一个例外情况是 bitflags。如果在定义enums或bool时使用bitflags,可以至少安全地增加成员到下个字节-1.例如:一个类有如下成员unsigned int m1 : 1;unsigned int m2 : 3;unsigned int m3 : 1;修改为unsigned int翻译 2021-08-11 16:17:03 · 184 阅读 · 0 评论 -
C++二进制兼容性总结
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、什么是二进制兼容?二、保持二进制兼容的条件1.可以做的事情2.不可以做的事情补充说明应该做的总结前言对于C-Like等编译型语言,没有虚拟机的协助,随着项目维护,必然会产生很多兼容性问题。此文作为个人对其中的二进制兼容性进行一下总结。一、什么是二进制兼容?对于一个库,如果使用旧版本的主程序,无需重新编译就可以连接新版本的库,并正常运行,则这个库是二进制兼容的。如果主程序不需要修改,但需要重新编译才可以使用新版翻译 2021-08-11 14:33:35 · 2412 阅读 · 0 评论 -
设计模式-外观模式
适用情境:对客户端屏蔽各个子系统的细节,使用户可以用统一的接口使用子系统.// subsystema.h#ifndef SUBSYSTEMA_H#define SUBSYSTEMA_Hclass SubSystemA{public: SubSystemA(); void MethodA();};#endif // SUBSYSTEMA_H// subsystema.cpp原创 2016-10-25 20:08:34 · 195 阅读 · 1 评论 -
设计模式-建造者模式
适用情境:创建复杂对象,使用单独类指导对象的创建.// product.h#ifndef PRODUCT_H#define PRODUCT_Hclass Product{public: Product(); virtual void Show();public: int m_iNumA; int m_iNumB;};#endif // PRODUCT_H/原创 2016-10-25 21:44:42 · 367 阅读 · 1 评论 -
设计模式-观察者模式
适用模式:多个观察者同时监听一个主题对象.// subject.h#ifndef SUBJECT_H#define SUBJECT_H#include #include "observer.h"class Observer;class Subject{public: Subject(); virtual void Attach(Observer * obse原创 2016-10-26 12:03:13 · 252 阅读 · 1 评论 -
设计模式-抽象工厂模式
适用情境:定义一个类,此类创建一系列相关接口.// product.h#ifndef PRODUCT_H#define PRODUCT_Hclass Product{public: Product(); virtual void Show() = 0;public: int m_id;};#endif // PRODUCT_H// product.cpp#inc原创 2016-10-26 15:52:38 · 198 阅读 · 1 评论 -
设计模式-单例模式
使用情境:确保一个类仅有一个对象实例.// singleton.h#ifndef SINGLETON_H#define SINGLETON_Hclass Singleton{private: Singleton(); static Singleton* single_instance;public: static Singleton* GetInstance();原创 2016-11-08 15:12:30 · 228 阅读 · 1 评论 -
设计模式-状态模式
适用情境:一个对象的运行时行为根据自身的状态不同而改变.// state.h#ifndef STATE_H#define STATE_Hclass Device;class State{public: State(); virtual void ShowState(Device * dev) = 0;};#endif // STATE_H// state.cpp#incl原创 2016-10-27 18:49:01 · 184 阅读 · 1 评论 -
设计模式-模板方法模式
适用情境:基类定义逻辑框架,子类实现具体步骤.// ctemplatemethod.h#ifndef CTEMPLATEMETHOD_H#define CTEMPLATEMETHOD_Hclass CTemplateMethod{public: CTemplateMethod(); virtual void TemplateProcess(); virtual voi原创 2016-10-24 19:41:31 · 196 阅读 · 1 评论 -
设计模式-原型模式
适用情境:一个对象复制自身.// prototype.h#ifndef PROTOTYPE_H#define PROTOTYPE_Hclass Prototype{public: Prototype(); Prototype(int id); virtual void Show(); virtual Prototype *Clone() = 0;privat原创 2016-10-24 13:55:03 · 209 阅读 · 1 评论 -
设计模式-组合模式
适用情境:把操作简单对象和复杂对象的接口统一,使得客户端使用组合对象和简单对象的方式一致.// component.h#ifndef COMPONENT_H#define COMPONENT_H#include class Component{public: Component(std::string strName); virtual void Add(Co原创 2016-11-03 23:38:54 · 203 阅读 · 1 评论 -
设计模式-工厂方法模式
适用情境:与简单工厂模式相比,由客户端做判断.// product.h#ifndef PRODUCT_H#define PRODUCT_Hclass Product{public: Product(); virtual void Show() = 0;};#endif // PRODUCT_H// product.cpp#include "product.h"Produc原创 2016-10-23 11:31:56 · 217 阅读 · 1 评论 -
设计模式-代理模式
适用情境:把真实请求处理类与客户端进行隔离// subject.h#ifndef SUBJECT_H#define SUBJECT_Hclass Subject{public: Subject(); virtual void Request() = 0;};#endif // SUBJECT_H// subject.cpp#include "subject.h"Subje原创 2016-10-23 09:58:57 · 166 阅读 · 1 评论 -
设计模式-装饰模式
适用情境:给一个类添加一些额外的功能,而不修改原来类的代码.添加的功能一般不是非常重要的核心功能,而是较少使用的次要功能.添加的功能放在一个单独的类中,客户端可以对添加的功能进行选择.优点:新添加的功能不影响被装饰类的功能,不增加被装饰类的复杂度. 缺点:需要修改客户端代码.// component.h#ifndef COMPONENT_H#define COMPONENT_Hclass Co原创 2016-10-22 18:50:53 · 226 阅读 · 1 评论 -
设计模式-备忘录模式
适用情境:在一个对象外部记录其状态,在对象状态改变后提供恢复以前状态的功能.// device.h#ifndef DEVICE_H#define DEVICE_H#include "memo.h"class Device{public: Device(); Memo* CreateMemo(); void Recover(Memo* memo); void S原创 2016-11-02 23:55:33 · 197 阅读 · 1 评论 -
设计模式-适配器模式
适用情境:在源接口和目标接口都不适宜修改的情况下,把源接口转换成目标接口.// target.h#ifndef TARGET_H#define TARGET_Hclass Target{public: Target(); virtual void Request();};#endif // TARGET_H// target.cpp#include "target.h"原创 2016-11-02 21:56:54 · 243 阅读 · 1 评论 -
设计模式(一):开放封闭原则
开放封闭原则:一个软件实体(如类、模块和函数)应该对货站开放,对修改封闭。开放封闭原则指的是:既然需求一定会随着时间发生变化,软件只有适应变化。但是,较好的方式是通过扩展软件实体的方式应对变化,而不是通过修改原有代码来适应变化。开放封闭原则要求对修改关闭,但不做任何修改也是不可能的。变化大概可分为如下类别:1.逻辑变化:一个业务逻辑具体的处理算法变化,而且是原创 2013-06-24 21:14:09 · 793 阅读 · 1 评论