减少编译时源文件之间的依赖

Go-Wire: Go编译时依赖注入工具详解与实战 Go-Wire 是一个用于 Go 语言的依赖注入库,它通过编译时生成代码来管理依赖关系,使得应用程序的结构更加清晰。依赖注入(DI)是一种设计模式,它将依赖关系从主体对象中分离出来,以便于测试和维护。在Go语言中,接口是一种定义方法集合的方式,它是一组方法签名的集合。接口的使用增强了程序的抽象性和模块化,允许开发者编写与具体实现无关的通用代码。在依赖注入的上下文中,接口定义了依赖的契约,使得不同的实现可以互换,同时隐藏了具体实现的细节。设计一个服务接口时,需要遵循以下几个原则:单一职责。 阅读详情

描述

     在大型项目开发中,往往编译时间非常长,我见过需要编译15分钟的项目,这对于开发人员来说无疑是无奈的等待。如果每次一个小的代码修改,整个项目都要重新编译的话,时间成本是非常高,为了说明这个问题,下面举一个例子:

 如下类:

A.hpp

class A
{
public:
    void foo();
 
private:
    AMember m_member;
}

      如果该头文件被包含在预编译头文件中,若修改类A,每个.cpp源文件都需要重新编译,因为A.h被预编译头文件包含,所有.cpp可能都需要类A。当我们修改类AMember,所有的文件也需要重新编译。当然上面的结果是我们不想要的,能不能只让包含AMember的源文件重新编译?下面将介绍如何让编译器只编译修改的部分。

       类的定义一般包含类的实现细节,如成员变量。上面的例子中包含成员变量AMember,因此A.hpp需要包含头文件AMember.hpp,如#include “AMember.hpp”,这无疑增加了编译的依赖,所以需要移除上面的编译依赖。为了减少这种依赖,下面介绍几种方法。

方法一:利用Handle类

该方法在Scott Meyers写的书籍《EffectiveC++》有描述,一个Hanldle类是包含一个具体实现类的对象,如下:

A.hpp

class AImpl;
class A
{
public:
    void foo();

private:
    AImpl * impl;//指向Handle类的指针
};

AImpl.hpp

#include “AMember.hpp”
class AImpl
{
public:
    void foo();

private:
    AMember m_member;
};

A.cpp

#include "AImpl.hpp"
#include “A.hpp”
void A::foo()
{
    impl->foo();
}

在头文件A.hpp中采用类前置声明AImpl,没有包含该类的头文件AImpl.hpp,主要是在头文件A.hpp中,只使用指向AImpl的指针,但在A.cpp中需要包含AImpl.hpp。该方法的缺点如下:

1.每个A对象需要一个额外的指针

2.需要在运行是重链成员函数

3.需要动态为AImpl分配内存。

方法二:利用Protocol类

Protocol类是一个抽象类,只代表具体类的一个接口。如下:

B.hpp

class B
{
public:
    virtual void foo() = 0;
    //由于该类为抽象类,不能直接实例化对象,需要提供一个方法实例化
    static B * makeB();
};

BImpl.hpp

#include "B.hpp"
#include “AMember.hpp”
class BImpl : public B
{
public:
    void foo();

private:
    AMember m_member;
};

B.cpp

#include  "BImpl.hpp"
#include "B.hpp"
B * B::makeB()
{
    return new BImpl;
}

从上面可以看到,源文件B.cpp只需要包含B.hpp和BImpl.hpp。该方法利用一个抽象类,并且提供一个实例化的接口来构造子类BImpl。

该方法的缺点如下:

1.需要一个辅助函数来构造一个对象

2.需要手工释放由辅助函数构造的对象。

3.使用了虚函数,需要提前加入虚表。

4.运行时链接虚函数。

方法三:利用模板

D.hpp

template <class T>
class TD
{
public:
    void foo();
};

// 前置声明一个类
class DImpl;

typedef TD<DImpl> D;

DImpl.hpp

#include "D.hpp"

class DImpl : public TD<DImpl>
{
public:
    void foo();

private
    AMember m_member;
};

D.cpp

#include "DImpl.hpp"

void TD<DImpl>::foo()
{
    (static_cast<DImpl *>(this))->foo();
}
void DImpl::foo()
{
	m_member.foo();
}

上面的TD的this指针指向DImpl.有了该指针,就可以访问该类的函数。

方法三与上面两种方法的对比:

与方法一对比:

     a.不需要额外的变量 

     b.在编译期间链接函数,不需要在运行期间。

     c.不需要手工申请和释放内存

与方法二对比:

      a.不需要辅助类进行对象实例化,可以通过TD<DImpl>.进行实例化。

      b.不需要手工释放对象,本方法对象管理和根据自身的初始化方式决定。

      c.没有虚表   d.没有虚函数,在编译期间进行链接。

      委屈注意:基于模板的方法三有一个Bug,当类DImpl包含数据成员时,本方法会失效。AMember的构造函数不会被调用,同时DImpl的构造函数也不会调用,丢失了C++的特性。如果一个类包含数据成员,不能使用方法三。

方法四:利用静态变量

E.hpp

//编译器不需要知道AMember的具体实现
class AMember;

class E
{
public:
    const AMember& GetMember();
};

E.CPP

#include "E.hpp"
#include "AMember.hpp"
const AMember& E::GetMember()
{
    static AMember member;

    return member;
}
void E::foo()
{
   GetMember().foo
}

     如果需要使用类AMember,只需要包含E.hpp,然后调用E::GetMember,本方法可以促使自己采用面向对象进行编程,可以减少依赖。由于使用了静态变量是、,类E只有一个实例化对象AMember,有点类似单例模式。

       总结上面的方法就是在编译时间和运行时间进行衡量,有的利用运行时间换编译时间,如动态分配内存和释放内存都会损耗运行时间,对于这类运行时间优化可以采用内存池技术。同时虚表也会降低运行速度。本文着重讲解减少编译时源文件之间的依赖。微笑

减少文件之间的编译依赖 讲述了在编写C++过程中,如何减少文件之间的编译依赖 立即下载

相关推荐

Frida实战:高效dump Android内存中的so文件与修复技巧

本文详细介绍了使用Frida工具dump Android内存中已解密so文件的实战技巧。针对加固应用静态分析失效的痛点,文章提供了从环境搭建、使用frida_dump脚本自动化抓取内存数据,到利用SoFixer工具修复ELF文件结构的完整流程,帮助逆向分析人员高效获取可分析的so文件。

tt34567的博客 527

微信小程序中主包和分包过大,详解分包问题

博文介绍了对于较大的项目而言,根据微信开发者工具中提示,从自用组件、官方组件、项目配置等方面提出分包、精简项目的见解。

qq_43638732的博客 8395

清理异常值(MAD:绝对中位差)

清理异常数据: 中位数绝对偏差(MAD):用来描述单变量样本在定量数据中可变的一种标准 在统计学中,绝对中位差是刻画一元数据样本变化的一个鲁棒度量。由公式可以看出,其求解还算简单,给定一个数据样本集,首先求其中位数,然后求原始数据减去中位数的绝对值从而形成一个新的数据样本,再求新的数据样本的中位数即为绝对中位差。比如说有一个数据样本集X={2 3 8 7 9 6 4},这时候数据的中位数是6,原...

spider_man 1万+

微信小程序打包时不应存在无依赖文件问题

微信小程序上传时的不应存在无依赖文件问题

m0_58969296的博客 1万+

手把手教你用WF100DPZ数字压力传感器搞定I2C/SPI通信(附完整寄存器解析)

本文详细解析了WF100DPZ数字压力传感器的I2C与SPI通信驱动方法,涵盖硬件连接、寄存器配置、数据读取流程及常见问题排查。该传感器内置24位ADC和出厂校准,通过实战代码演示了如何稳定获取高精度压力与温度数据,帮助开发者快速集成到嵌入式项目中。

weixin_28285943的博客 375

cellranger安装以及使用

接受cellranger count的输出数据,将同一组的不同测序样本的表达矩阵整合在一起,比如tumor组原来有4个样本,PBMC组有两个样本,现在可以使用aggr生成最后的tumor和PBMC两个矩阵,并且进行标准化去掉测序深度的影响。但是由于病毒基因组太小了,且注释结果只有CDS没有exon,所以曲线救国,将CDS整体替换为exon,也不进行过滤了,直接下一步。虽然安装完毕,但是现在要运行cellranger的话需要在终端输入cellranger的整个路径。自动执行这个命令,需要将“

m0_59974475的博客 9391

小程序 已被代码依赖分析忽略,无法被其他模块引用。你可根据控制台中的【代码依赖分析】告警信息修改代码,或关闭【过滤无依赖文件】功能

最近刚换工作,接手的之前的项目,也没有任何交接,蓝瘦香菇...领导发了一个之前的小程序zip项目包,我解压后开发工具打开,页面加载不出来,控制台报如下问题“已被代码依赖分析忽略,无法被其他模块引用。刚开始看控制台返回的信息,以为是需要在 开发工具 右上角“详情”=>“本地设置”=>“上传时过滤无依赖文件”关闭即可,但是反复尝试后,发现并没卵用,最后查阅了文档,才找到方法。”,也就是将一些需要的依赖被分析为无依赖文件过滤掉了,导致渲染时获取不到相关依赖,页面无法访问,如下图所示。

鹏仔工作室的秘密基地 2万+

系统-等保三级-CentOS Linux 7合规基线检查 shell脚本

系统-等保三级-CentOS Linux 7合规基线检查 shell脚本

swindy博客 2407

uni-app 微信小程序打包,无依赖文件 处理方法

方法1.删除掉,点击查看,选中文件右键删除。 方法2:根据条件编译,比如我有个配置文件在h5用到了,在static下新建h5文件夹,将无依赖文件移到h5文件夹,在入口文件修改引入地址为./static/h5/config.js,这样微信小程序打包时不会被编译 ...

weixin_45753961的博客 1万+

香橙派5使用RK3588S内置NPU加速yolov5推理,实时识别数字达到50fps

香橙派5采用了RK3588S,内置的NPU达到了6Tops的算力,博主这里记录一下自己的踩坑过程,好不容易做出来的不能以后忘记了(手动狗头)。这里博主还在B站上发布了效果视频,大家感兴趣的话可以看一下。其中解决了先验框标注位置不对,或者出现非常多的框的问题

weixin_51651698的博客 2万+

ITKMontage---ITK自动拼接模块

本文分享ITK中Remote中的ITKMontage拼接模块,希望对各位小伙伴有所帮助!1. ITKMontage介绍在医疗图像处理过程中,图像拼接有很多用处,比如DR图像的拼接。ITKMontage可以快速稳定的处理数据量较大的拼接图像。强度不均匀性校正配准全局优化融合2. ITKMontage安装ITKMontageITKMontage可脱离ITK进行单独安装,也可在ITK安装时作为模块进行安装。单独安装ITK模块安装在ITK编译时,选择ITKMontage模块。

qq_40041064的博客 449

微信小程序-上传代码失败,提示分包大小超过限制

因此我们建议开发者在开发时,如果遇到单包体积大于1.5M的情况,可以采取分包的方式,把部分代码拆分到分包去,降低单个包的体积,提升小程序的加载速度。【知会】小程序插件的大小是会算进小程序代码包2M体积限制中的。【必须】在「代码质量」面板,点击「建议去除」后,可以打开代码依赖分析面板的「无依赖文件」页面,这里可以看到代码包里没有被用到的文件。【建议】当主包里存在一些JS文件只会被分包使用(而主包自己不使用)时,我们建议把这些JS文件从主包中拆分出去,放到对应的分包里,从而优化主包的加载速度。

weixin_64051447的博客 1万+

从 Product Master 视角理解 Configurable Products

摘要:SAP S/4HANA中的可配置产品(Configurable Products)通过集中管理产品变体解决主数据膨胀问题。以汽车和服务器为例,销售端显示为单一产品,生产端则处理多维度组合。核心机制包括:1)使用KMAT物料类型或Configurable标记;2)通过特征(characteristics)定义可选项;3)用分类(class)组织特征;4)配置档案(configuration profile)控制业务逻辑。这种设计将客户选择与主数据解耦,避免为每个组合创建独立物料,同时支持销售配置、生产B

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 83

外部依赖项、头文件、源文件、资源文件

当我们刚开始写代码的时候,往往先进入这样一个界面,里面有四个文件夹,分别是外部依赖项、头文件、源文件、资源文件,那它们都有什么样呢?本文将具体介绍这四个文件夹的作用。

m0_74195174的博客 3842

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

减少编译时依赖的意义和一些惯用法

原文参见: GotW #7a Solution: Minimizing Compile-Time Dependencies, Part 1 2013-08-19 by Herb Sutter http://herbsutter.com/2013/08/19/gotw-7a-solution-minimizing-compile-time-dependencies-part-1/ GotW

fengxinze的专栏 1149

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

java编程惯用法_减少编译时依赖的意义和一些惯用法

http://herbsutter.com/2013/08/19/gotw-7a-solution-minimizing-compile-time-dependencies-part-1/GotW #7a Solution: Minimizing Compile-Time Dependencies,Part 12013-08-19 by Herb Sutter减少编译时依赖的意义和一些惯用法1. ...

weixin_35541322的博客 155

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Sword:编译时依赖注入库,让Swift开发更简洁高效

Sword:编译时依赖注入库,让Swift开发更简洁高效 项目介绍 Sword 是一个专为 Swift 设计的编译时依赖注入库。它受到了知名依赖注入框架 Dagger 的启发。Sword 通过使用 Swift 宏,在编译时自动生成依赖注入代码,从而避免了运行时错误。它能够遍历代码并验证依赖关系图,确保每个对象的依赖可以被满足。 项目技术分析 Sword 采用了 Swift 的宏功能,这是一个在编译...

gitblog_00495的博客 1071

android编译依赖_Android中的编译时依赖注入权衡

android编译依赖 作为后端软件开发人员,我习惯于使用Spring作为我最喜欢的依赖注入引擎。 替代方案包括Java EE的CDI ,它以不同的方式获得相同的结果。 但是,两者都在运行时注入:这意味着在应用程序启动时要付出一定的性能成本,这是所有依赖关系得到满足所需的时间。 在应用程序服务器上,以天数(如果不是几周)来衡量应用程序寿命,则可以接受启动时间开销。 如果服务器只是大型群集中的一个...

dlz00001的博客 362

android 编译时依赖包,Android编译依赖项

implementation:(代替compile)Gradle 会将依赖项添加到编译类路径,并将依赖项打包到编译输出。不过,当您的模块配置 implementation 依赖项时,会让 Gradle 了解您不希望该模块在编译时将该依赖项泄露给其他模块。也就是说,其他模块只有在运行时才能使用该依赖项。使用此依赖项配置代替 api 或 compile(已弃用)可以显著缩短编译时间,因为这样可以减少编...

weixin_36145482的博客 840

探索 TypeScript 的编译时依赖注入:@wessberg/di

探索 TypeScript 的编译时依赖注入:@wessberg/di 在现代软件开发中,依赖注入(Dependency Injection, DI)已经成为一种不可或缺的设计模式。它不仅简化了代码的复杂性,还提高了代码的可维护性和可测试性。今天,我们将介绍一个专为 TypeScript 设计的编译时依赖注入容器——@wessberg/di,它以其独特的设计和强大的功能,正在成为 TypeScri...

gitblog_00380的博客 912

Java编译时注解应用-生成格式化源文件

引言 有许多开源框架在编译时通过注解信息生成新的源文件,已到达简化样板代码的书写,比如说典型的Builder模式,或者实现框架的功能的桥接代码。因为我使用编译时注解只是想要简化样板代码,下面我就以Builder模式作为示例。 Builder模式 Builder模式主要是解决创建对象过程中的必须参数和非必须参数的的传入,以及以及传入过程中导致对象的中间状态暴露在外面。下面是简单Builde...

sOSky 1278

Needle:编译时安全的Swift依赖注入框架完全指南

Needle是一款专为Swift开发者打造的编译时安全依赖注入(DI)框架,它通过在编译阶段验证依赖关系,帮助开发者构建更稳定、可维护的iOS应用。本文将带你全面了解Needle的核心优势、安装方法和实际应用技巧,让你轻松掌握这一强大工具。 ## 🚀 为什么选择Needle?核心优势解析 ### 编译时安全:提前规避依赖问题 Needle最突出的特点是其**编译时安全保障**。传统依赖注入

gitblog_00544的博客 841

spdlog编译时计算:减少运行时的开销和计算

在现代C++高性能应用中,日志记录往往是性能瓶颈之一。传统的运行时日志处理需要解析格式字符串、检查日志级别、分配内存等操作,这些都会带来显著的开销。spdlog作为业界领先的C++日志库,通过巧妙的编译时计算技术,将大量工作从运行时转移到编译时,实现了近乎零开销的日志记录体验。 读完本文,你将掌握: - spdlog编译时日志级别过滤的实现原理 - fmtlib编译时格式字符串解析的机制 - 如...

gitblog_00698的博客 645

探索teloc:Rust的编译时依赖注入框架

探索teloc:Rust的编译时依赖注入框架 teloc是一个灵感来源于C#依赖注入框架的轻量级、高性能的Rust库。它利用了Rust强大的类型系统,在编译期间检查和管理依赖关系,确保你的代码在运行时无误。 项目简介 teloc致力于简化Rust应用程序中的依赖管理。通过依赖注入(Dependency Injection)机制,对象可以接收并使用由外部提供的服务,无需直接创建或知道服务的具体实现。...

gitblog_00097的博客 642

怎样降低文档之间的依赖性

 今天读了effective C++,很受启发<!--function fullSize(sURL){ window.open(sURL,scrshot,width=500,height=375,top=20,left=20,directories=no , Toolbar = no, resizable = yes, menubar = no, ScrollBa

bestwolf_yan的专栏 294

C++ 中减少依赖与提升编译效率的几种方式

如果你希望不同的类遵循相同的协议或行为,可以定义一个接口(即纯虚类)。通过接口,多个类可以共享一组方法签名,而不必关心它们的具体实现。这种方法也能有效地解耦类与类之间的关系。在 C++ 中,随着项目规模的增大,管理类之间的依赖关系成为提高编译效率和维护性的重要任务。通过合理地使用前向声明PImpl 模式接口/抽象类模板和 friend关键字等方式,开发者可以有效地减少不必要的头文件包含、避免循环依赖,并优化编译时间。选择适合的策略可以大大提高代码的可维护性和编译效率。

thing 651
上一篇: 基于Table方法降低代码圈复杂度
下一篇: 一个移位操作引发的程序Bug
xiaoding133
博客等级 码龄19年 415粉丝 159原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值