提升C++项目编译速度

目录

一、问题背景

二、代码规范方面的解决方案

2.1 拆分头文件

2.2 拆分巨型类

2.3 使用前置声明

2.4 避免在头文件中包含实现 

2.5 避免头文件重复包含

2.6 将常用且变动较少的独立到一个文件 

三、代码业务重构方面经验

3.1 使用PIMPL(Pointer to Implementation)技术

3.2 单例模式的使用

3.3 模板模式的使用 

3.4 工厂模式的使用

3.5 备忘录模式的使用

3.6 职责链模式的使用

3.7 适配器模式的使用

3.8 插件的使用

四、总结 


一、问题背景

        在日常停车管控软件开发中,随着不同人员添加新的功能、接入新的设备;程序代码越来越臃肿,每一次全量编译都将近一个小时,甚至修改极少的代码编译也几乎要近一个小时,严重影响开发效率。

二、代码规范方面的解决方案

        为了提升编译速度,主要从以下几个方面对代码进行了部分重构和优化,优化后的项目全量编译约二十分钟,极大提升了开发进度。

2.1 拆分头文件

        随着项目需求的不断递增、新设备、新平台、新服务接口等不断接入,项目组成员之间负责功能模块不同,逐渐出现了一些巨型头文件,且这些巨型头文件被包含在近乎所有的模块中,导致这种文件每新增一些内容就会引发几乎所有模块重新编译。

        本着功能模块的原则,将这些巨型头文件按照模块进行拆分,分别归入到不同的功能模块下,并规范后续开发新增模块功能需自增头文件,避免出现包含内容过多的头文件。

2.2 拆分巨型类

        在优化项目过程中发现使用频次很高的类成员特别多,功能特别全面;许多新增的需求也会有人关联到这种常用类中,这也导致这种类由于功能过于全面,项目中到处都是,稍微修改即会引发大量相关文件重新编译。

        本着将功能模块尽量细分的原则,一个类的功能尽量单一,将这种较大的巨型类逐渐细化拆分,降低不同文件之间的依赖。

2.3 使用前置声明

        由于项目组里不同人员开发习惯不同,一部分开发人员定义的头文件包含了过多的头文件,导致文件之间的依赖性和编译时间恶化。

        在项目优化中逐渐优化头文件的包含文件,去除不相关的头文件,其余相关的头文件大部分头文件实际上也没必要包含,只需要声明即可,在实现文件中在包含相应的头文件可以极大的降低头文件与其他文件之间的依赖关系。如下面代码所示:

// 在头文件中,尽量使用前置声明,而不是 #includeclass ClassA;  // 前置声明
class ClassA;  
class ClassB 
{    public:ClassA* myObject;  // 使用指针或引用,不需要完整定义
};

2.4 避免在头文件中包含实现 

        项目组中存在开发人员因为所新增的功能及其简单,遂将实现的实际细节逻辑一并写在头文件中,后续随着需求的复杂化和多样化后续开发人员逐渐在该基础上进行逻辑补充,导致该头文件剧烈变化,从而几乎每次新down下的代码重新编译都会因为这种头文件变动导致依赖的文件均重新编译,一定程度拖慢整体开发效率。

        后续逐步将程序中头文件中的细节实现移动到对应的实现cpp文件中,将项目中头文件的定义与实现细节拆分;后续以此为规范,代码评审环节进行检测。

2.5 避免头文件重复包含

        头文件通常包含在多个源文件中,规范头文件代码具有防止重复包含的设计,可以使用#pragma once或者宏。

// 使用 include 守卫
#ifndef _CLASSA_H_
#define _CLASSA_H_
class ClassA {   // 类定义
};#endif  // _CLASSA_H_

2.6 将常用且变动较少的独立到一个文件 

        项目中有一些与业务不想关的代码,如sdk的启动加载、设备的登录登出、一些必要库的加载,一些工具类的函数等等,将这些代码抽离到一个固定的头文件中,可以避免其他业务代码的变动引起这些比较固定的相关代码的重新编译。

三、代码业务重构方面经验

        除却以上几种之外,实际项目中最复杂的还是业务部分代码,该部分代码随着设备的升级、新增,需求的升级新增、接入平台、开放接口功能等等急剧变化,不但引起了整体代码框架的不稳定,同时也会逐渐增加文件之间的依赖,日积月累,积重难返编译时间也会越来越长。

        在程序优化过程中逐步对各个模块进行梳理,引入设计模式对业务代码进行优化,以下是一些优化经验。

3.1 使用PIMPL(Pointer to Implementation)技术

        对于一些业务变动比较剧烈的函数,使用PIMPL技术后者直接上d指针进行变动业务的重构,将具体的业务细节代码隐藏在实现中,对外仅仅是一个比较稳定的指针接口,可以大幅的降低由于业务代码变动引起的相关文件跟着变动,从而导致编译时间拉长、代码框架不稳定等你问题。具体参见以下博文。

https://blog.csdn.net/WSTONECH/article/details/143989953文章浏览阅读282次。Pimpl(pointer to implementation, 指向实现的指针)是一种用来对“类的接口与实现”进行解耦合的方法。就是将真正的实现细节的Implementor从类定义的头文件中分离出去,公有类通过一个私有指针指向隐藏的实现类,是促进接口和实现分离的重要机制,可以避免在头文件中暴露私有细节。Pimpl 并不是严格意义上的设计模式(它是受制于 C++ 语言特定限制的变通方案),这种惯用法可以看作的一种特例。私有成员完全可以隐藏在共有接口之外,尤其对于闭源API的设计尤其的适合。_d指针 https://blog.csdn.net/WSTONECH/article/details/143989953

3.2 单例模式的使用

        在梳理业务项目过程中,各个模块不同程度的使用了单例模式;但由于是不同人员开发,实现方式也各不相同,导致代码中充斥着各种参差不齐的单例实现,有的甚至并非线程安全。对此在优化过程中结合模板技术,引入单例模板,逐步替换掉各个功能模块的单例实现,不仅使代码更加简洁清晰,也提高了程序中单例的可维护性,具体参见以下博文。

 创建型模式-----(单例模式)-CSDN博客文章浏览阅读1.2k次,点赞7次,收藏6次。本文主要描述了设计模式中单例模式的两种形式,着重介绍了懒汉式单例的几种实现方式和优劣,最后介绍了一种通过局部静态变量实现的单例模板,以及该模板在项目中的应用。 https://blog.csdn.net/WSTONECH/article/details/143158151

3.3 模板模式的使用 

        在梳理业务项目过程中,发现不少代码功能相似的代码,如不同省份的ETC接入扣费模块,虽然各个省份的接入协议具体接口数量、类型和通信方式不尽相同,但是从业务上划分基本均可分为定时上报信息相关、实时过车上报信息相关、实时扣费相关等,据此引入模板模式重构此部分代码,不仅提升了代码的可维护性,避免不同省份不同开发人员可能引入的与其他无感支付竞态问题,而且极大缩减了代码量,一定程度提升编译时间性能,具体参考以下博文。

组件写作-----模板模式-CSDN博客文章浏览阅读801次。模板模式利用虚函数的多态和稳定的任务流程模板,可以在需求变化时,只需要继承模板,将开发精力集中到具体的实现步骤即可。 https://blog.csdn.net/WSTONECH/article/details/143634388

3.4 工厂模式的使用

        在梳理设备相关业务过程中,从代码改动痕迹可以看的出,新型设备逐年接入,设备类型、接入方式越来越复杂,导致程序里面设备相关代码相当混乱,无论是定制修改设备相关功能或者增加新的设备接入都会引起一大堆文件的变动,代码可维护性较差,而且改动会引起想打一部分文件重新编译,一定程度拖慢编译时间,本着将业务变化与框架不变进行隔离,将业务变化控制在一定范围的原则,该部分代码引入工厂模式进行重构,具体参考以下博文。

创建型模式-----工厂模式_abstractdevice-CSDN博客文章浏览阅读946次。工厂模式主要是定义一个创建对象的接口,通过虚函数让子类决定实例化具体的对象,使得类的实例化延迟到子类中,从而达到解耦的目的。_abstractdevice https://blog.csdn.net/WSTONECH/article/details/143208105

3.5 备忘录模式的使用

        在项目车道相关的代码梳理中发现不少的代码冗余,且界面代码与业务代码关联过于密切,导致维护改动不易,且改动容易引发连锁反应导致一部分文件跟着变动;梳理该部分业务,对车道界面和车道设备业务代码进行分离引入备忘录模式,所有车道公用一套车道UI代码,将车道上设备配置等业务信息以不同的状态存储,从而达到UI和设备配置相关代码分离的目的,提高了代码的可维护性,降低耦合度,一定程度提高了编译效率,具体可参考以下博文。

项目优化之备忘录模式-CSDN博客文章浏览阅读1k次。在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便于在不同时机可以切换到不同的状态中。 https://blog.csdn.net/WSTONECH/article/details/144675792

3.6 职责链模式的使用

        在项目支付相关的模块存在多种无感支付方式,之前的代码为了避免无感支付的竞态将多个无感支付方式轮询同步调用,不同支付方式之间耦合度极高,若现场新增或要求支付优先级与设定方式不同则需要修改几乎所有支付方式之间耦合部分代码,可维护性较差且耦合度高不利于代码的编译效率。为了降低各个无感支付之间的耦合度以及该部分的可维护性,优先级的可控从而引入职责链模式,配合优先级配置项可以实现各个支付方式之间解耦合,优先级可调,并且一定程度上提高编译效率,具体可参考以下博文。

项目优化之职责链模式应用-CSDN博客文章浏览阅读684次。职责链模式,是一种行为型模式,使多个对象构成对象链,将一个请求传递给对象链,哪个对象适合处理这个请求就让哪个对象来处理,可避免请求的发送者和接收者之间的耦合关系。如果请求在对象链上节点处理后仍可以往下传递,这种每个节点只处理一部分的职责链即是功能链,类似于流水线每个站点只处理任务的一部分,到流水线尽头任务即完成。职责链模式的优点发送者和接收者不需要知道彼此的具体细节。可以动态地添加或修改处理链,而不影响其他部分。请求可以被多个对象处理,不必绑定到特定的处理者。 https://blog.csdn.net/WSTONECH/article/details/144859256

3.7 适配器模式的使用

        对于一些类型的设备,设备型号、类型等不断更新换代,但是作为停车软件使用这些设备的基本功能基本稳定,如LED设备的显示,使用场景和方式比较固定,但是程序中针对不同设备的功能接口不统一,一方面不便于业务代码中使用,另一方面代码耦合较高,改动容易影响编译效率。因此根据业务功能制定统一的接口,结合适配器类型将不同类型型号的LED设备进行接口适配,将设备的底层代码和对外业务接口隔离,降低了代码之间耦合,提高可维护性,一定程度也提升了编译效率,具体可参考以下博文。

结构性设计模式-----适配器模式-CSDN博客文章浏览阅读894次,点赞8次,收藏2次。将一个类的接口转换为客户希望的另一个接口,Adapter模式使得原本由于接口不兼容的类不能一起工作的类可以一起工作。 https://blog.csdn.net/WSTONECH/article/details/144660558

3.8 插件的使用

        对于一些停车场实际并不需要对接云或者开放接口,这部分功能由于接口相对稳定,在项目优化过程将其与主程序隔离,使用插件技术在插件中完成该部分逻辑迁移。一方面对接接口的改动不影响主程序,另外一方面对接功能与主程序剥离便于插件在不同版本程序上迁移,最后由于是分开编译,一般只要不修改对接云和开放接口部分均不需要编译这两部分代码,很大程度的提高了编译效率,具体可参考如下博文。

Qt中插件的使用_qt插件-CSDN博客文章浏览阅读913次。插件是一种(遵循一定规范的应用程序接口编写出来的)程序,定位于开发实现应用软件平台不具备的功能的程序。插件必须依赖于应用程序才能发挥自身功能,仅靠插件是无法正常运行的;相反地,应用程序并不需要依赖插件就可以运行,这样一来,插件就可以加载到应用程序上并且动态更新而不会对应用程序造成任何改变(热更新)。插件就像硬件插卡一样,可以被随时删除、插入和修改,所以结构很灵活,容易修改,方便软件的升级和维护。_qt插件 https://blog.csdn.net/WSTONECH/article/details/143802965?sharetype=blogdetail&sharerId=143802965&sharerefer=PC&sharesource=WSTONECH&spm=1011.2480.3001.8118

四、总结 

        提高程序编译效率一方面从代码文件管理方面不断降低不同文件之间的依赖关系,另外一方面从代码的业务层面剥离剧烈变动的业务逻辑和相对稳固的代码框架,尽可能的将变化部分小范围可控,尽可能的降低耦合度,这方面设计模式的使用是一个不错的选择。此外一些编译器上的配置如开启多核编译等以及一些加速编译的工具也有一定的效果,此处不详谈这方面。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/22634.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【学术投稿-第四届材料工程与应用力学国际学术会议(ICMEAAE 2025】材料工程与应用力学的探讨

重要信息 官网:www.icmeaae.com 时间:2025年3月7-9日 地点:中国西安 简介 第四届材料工程与应用力学(ICMEAAE 2025)将于2025年3月7日至9日在中国西安召开。本次会议将重点讨论材料科学、应用力学等领域的最新研究进…

抓包工具(三)Wireshark代理抓包Java程序的HTTPS请求

目录 一、需求背景二、操作步骤2.1 jSSLKeyLog 工具下载2.2 jSSLKeyLog工具使用2.3 将sslkeylog导入Wireshark2.4 测试Demo2.5 测试结果1)使用工具解密HTTPS前:2)实用工具解密HTTPS后: 三、补充:如果出现未解密成功的情…

[VSCode]彻底卸载和重装,并搭建Java开发环境

VSCode彻底卸载 由于当初是朋友帮忙装的,所以准备卸载,自己装一遍 从控制面板找到 vscode 将其卸载。 此时仅仅是删除了应用软件 删除安装插件 在图示路径中找到 .vscode 文件夹,将其删除,即可彻底清除安装的插件 C:\Users\user\.vscode …

泛微OA编写后端Rest接口

泛微OA编写后端Rest接口 前言 具体实现 运行结果 注意要点 总结 前言 在泛微E9中,可以通过注解的方式来编写对外的接口,之前的版本都是通过编写servlet类,然后在web.xml文件中将这个类和访问路径进行编辑之后才好在浏览器中通过输入对应…

041集——封装之:新建图层(CAD—C#二次开发入门)

如图所示&#xff1a;增加一个图层“新图层”&#xff0c;颜色为红&#xff08;1&#xff09;&#xff0c;当图层颜色定义为黄&#xff08;2&#xff09;时&#xff0c;直接覆盖之前图层颜色&#xff0c;图层名不变。 代码如下&#xff1a; /// </summary>/// <param …

Redis存储⑪主从复制_分布式系统解决单点问题

目录 1. 主从复制的概念 1.1 分布式解决单点问题 1.2 主从复制的特点 2. 模拟配置主从复制 2.1 建立复制 2.2 断开复制 2.3 安全性 2.4 只读 2.5 传输延迟 3. 主从复制的拓扑 3.1 一主一从结构 3.2 一主多从结构 3.3 树形主从结构 4. 主从复制的原理 4.1 复制过…

XiaoMi Mi5(gemini) 刷入Ubuntu Touch 16.04——安卓手机刷入Linux

最近在研究个人用的小服务器&#xff0c;期间也搞了一台某讯的盒子&#xff0c;s905的芯片&#xff0c;28G&#xff0c;刷入了Armbian&#xff0c;在自己本地当linux服务器用用挺方便的&#xff0c;但总感觉性能不太够。 然后灵机一动&#xff0c;手上还有几台旧的安卓手机&am…

SpringCould+vue3项目的后台用户管理的CURD【Taurus教育平台】

文章目录 一.SpringCouldvue3项目的后台用户管理的CURD【Taurus教育平台】 1.1 背景 二.用户列表&#xff08;分页查询&#xff09; 2.1 前端Vue3 &#xff08;Vue3-Element-Admin&#xff09;2.2 后端SpringCould 处理 三. 用户信息删除 3.1 前端Vue3 &#xff08;Vue3-Eleme…

HackTools插件+反弹shell的27种方法

前言 在渗透测试过程中&#xff0c;我们往往要使用很多命令&#xff0c;比如反弹shell、xss测试语句、sql测试语句、Linux常用提权语句、PowerShell常用语句。 为了方便&#xff0c;这里给大家推荐一个插件&#xff1a;HackTools&#xff0c;里面涵盖了渗透测试各种常用的语句…

Java语法-IO流

Java语法 Java基础语法 IO流 一、File类 /* java.io.File 文件类 提供了用于操作文件 创建文件 获取文件信息等 各种文件相关的方法 exists() 判断文件或目录是否存在 boolean isFile() 判断是否是文件 boolean isDirectory() 判断是否是目录 String getPath(…

Microsoft Office 2024 软件安装教程(免费)

1.通过百度网盘下载Microsoft Office 2024安装包 下载地址为: https://pan.baidu.com/s/1jk1kvQsKFH9dZGF5xfGgiQ?pwdjbkv 提取码: jbkv 。 2.安装环境 Win10~Win11或更高。 3.安装步骤 &#xff08;1&#xff09;下载压缩包&#xff0c;解压缩。 &#xff08;2&#xf…

鸿蒙NEXT应用App测试-专项测试(DevEco Testing)

注意&#xff1a;大家记得先学通用测试在学专项测试 鸿蒙NEXT应用App测试-通用测试-CSDN博客 注意&#xff1a;博主有个鸿蒙专栏&#xff0c;里面从上到下有关于鸿蒙next的教学文档&#xff0c;大家感兴趣可以学习下 如果大家觉得博主文章写的好的话&#xff0c;可以点下关注…

【学习笔记】【SpringCloud】MybatisPlus 基础使用

目录 一、使用 MybatisPlus 基本步骤 1. 引入 MybatisPlus 依赖 2. 定义Mapper接口并继承BaseMapper 二、MybatisPlus 常用配置 三、自定义SQL 四、IService 接口 1. 批量新增的效率问题 2. 配置方式 五、插件功能 1. 分页插件 一、使用 MybatisPlus 基本步骤 1. 引…

球队训练信息管理系统设计与实现(代码+数据库+LW)

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装球队训练信息管理系统软件来发挥其高效地信息处理的作用&a…

使用Dify将AI机器人嵌入到你的前端页面中及chrome的扩展应用

目录 1 博主有话说2 前提环境3 Dify创建个聊天助手应用4 将AI聊天机器人嵌入到html中5 将AI聊天机器人设置为chrome的扩展应用6 博主增语 1 博主有话说 那博主话不多说&#xff0c;先展示一下成果&#xff01; 这个界面是使用dify配置的一个“聊天助手”的应用&#xff0c;助…

Oracle JDK、Open JDK zulu下载地址

一、Oracle JDK https://www.oracle.com/java/technologies/downloads/ 刚进去是最新的版本&#xff0c;往下滑可以看到老版本 二、Open JDK的 Azul Zulu https://www.azul.com/downloads/ 直接可以选版本等选项卡

PiscTrace开发者版:只需考虑算法的视图处理应用

在计算机视觉领域&#xff0c;处理图像和视频数据的需求日益增长。无论是在智能监控、自动驾驶&#xff0c;还是工业检测中&#xff0c;图像处理都扮演着至关重要的角色。基于 OpenCV 的视图处理工具&#xff0c;专为需要高度定制和精确图像处理的开发者而设计。 一、CodeTrac…

线性回归 (Linear Regression)基础知识1

本章节主要介绍&#xff1a;回归任务简介、线性回归模型、回归任务的损失函数 *回归任务*机器学习的三要素线性回归线性回归模型 *数据分析*散点图*相关性系数矩阵 *拓展知识&#xff1a;相关性系数矩阵定义计算相关性系数矩阵示例应用 线性回归的损失函数回归任务目标函数&…

直角三角堰计算公式

直角三角堰的计算公式通常用于确定流经直角三角形形状的堰的流量。河北瑾航科技遥测终端机 通过采集液位数据(模拟量、串口485/232)&#xff0c;计算得到瞬时流量&#xff0c;然后通过积分进行累计算出累积量&#xff1b;直角三角堰的流量计算公式为&#xff1a; 直角三角堰 计…

《深度学习实战》第2集:卷积神经网络(CNN)与图像分类

《深度学习实战》第2集&#xff1a;卷积神经网络&#xff08;CNN&#xff09;与图像分类 引言 卷积神经网络&#xff08;Convolutional Neural Network, CNN&#xff09;是深度学习在计算机视觉领域的核心工具。从早期的 LeNet 到现代的 ResNet 和 Vision Transformer&#xf…