重构 C++ 代码以使用前向声明
Posted
技术标签:
【中文标题】重构 C++ 代码以使用前向声明【英文标题】:Refactoring C++ code to use forward declarations 【发布时间】:2010-02-19 16:32:08 【问题描述】:我有一个已经存在了一段时间的大型代码库,我正试图通过重构它来稍微整理一下。我想做的一件事是找到我可以转发声明成员的所有头文件,而不是包括整个头文件。
这是一个相当耗费人力的过程,我正在寻找一种工具来帮助我确定哪些标头具有可以向前声明的成员。
是否有编译器设置可以发出警告或建议以下代码可以使用前向声明?我正在使用以下编译器 icc、gcc、sun studio 和 HP 的 aCC
是否有可以完成相同工作的独立工具?
#include "Foo.h"
...//more includes
class Bar
.......
private:
Foo* m_foo;
;
【问题讨论】:
如果能开发出这样的工具就好了。如果它还可以指出我项目中的所有全局变量,我也会很高兴 - 它们是我们代码库中线程化的主要障碍。 谨慎地将#include
转换为前向声明。源文件需要有#include
。
@Lyndsey:DMS(请参阅我对这篇文章的回答)可以轻松挑选出您的全局变量。它可以配置为修改对全局变量的所有访问,对包含这些全局变量的线程局部实例的“上下文”结构的访问。
太好了,我会收藏它并检查一下。谢谢。
这些最后都起作用了吗?这也是我想在工作中做的事情。
【参考方案1】:
任何涉及 C++ 精确分析的事情基本上都需要某个地方的完整 C++ 前端(否则您将得不到答案,或者它们会出错,并且当您有“大型”应用程序时效果不佳)。这里没有很多实用的答案。
已经提到的是 GCCXML 是一个 GCC 派生的包,所以它有必要的 C++ 前端。它产生 XML,因此它将产生大量输出,您必须读回这些输出以形成另一个答案中建议的“内存数据结构”。不幸的是,GCCXML 已经构建了该内存数据结构,然后将其导出为 XML,并迫使您再次构建它。当然,您可以只使用构建内存数据结构的 GCC,但是您必须将 GCC 破解为您想要的,它真的,真的想成为一个编译器。这意味着您将面临一场斗争,以使其服从您的意愿(并解释为什么 GCCXML 存在:大多数人不希望这场斗争)。
没有提到的是 Edison Design Group C++ (EDG) 前端,它直接在内存数据结构中构建。它是前端;您必须自己完成所有分析工作,但您的任务可能很简单,所以并不难。
我知道的最后一个解决方案是我的:C++ FrontEnd for DMS。 DMS 是构建程序分析的基础,它的 C++ FrontEnd 是一个完整的 C++ 前端(例如,完成 GCC 和 Edison 前端所做的一切:解析、树构建、名称/类型解析)。而且,您必须通过遍历 DMS 生成的“内存中”数据结构来像对 GCCXML 和 EDG 一样对您的特殊分析进行编码。
真正不同的是,DMS 可用于通过更新内存数据结构中的源代码来实际修改源代码,并从这些内存结构(包括原始 cmets)重新生成可编译代码。
【讨论】:
【参考方案2】:我不确定您是否会找到开箱即用的功能,但一种选择是使用 Python 和 pygccxml 包编写一个脚本,它可以为您完成一些分析。
基本上,您将使用 pygccxml 构建源代码的内存图,然后使用它来查询您的类和函数,以找出它们实际需要包含的功能。
因此,例如,您可以询问每个类,给我指针类型的成员:然后对于这些指针类型中的每一个,您可以计算出接口中是否使用了该类的真实实例(非指针),并且如果不是,您可以将其标记为前向声明的候选对象。
缺点是脚本需要一些时间才能正确完成,因此成本可能超过收益,但至少这将是一个有趣的练习。如果你有一些有用的东西,你可以将你的代码发布到 Github,也许其他人会觉得它有用。
【讨论】:
+1 提到 pygccxml:不知道,看起来不错!【参考方案3】:你可以做的是用 -MM 调用 gcc。这将生成 Make 可以读取的依赖文件。不用 make 使用它们,您可以解析它们(使用 perl 或其他东西)以确定需要哪些包含,哪些可以用前向声明替换。
【讨论】:
@curlingdude:听起来是个有趣的想法 +1以上是关于重构 C++ 代码以使用前向声明的主要内容,如果未能解决你的问题,请参考以下文章