重构 C++使用前向声明的代码
我有一个已经存在了一段时间的大型代码库,我正在尝试通过重构来整理它。我想做的一件事是找到可以转发声明成员的所有标头,而不是包括整个标头文件。
这是一个相当劳动密集型的过程,我正在寻找一种工具,可以帮助我找出哪些标头具有可以向前声明的成员。
是否有编译器设置可以发出警告或建议,提示以下代码可以使用前向声明?我正在使用以下编译器 icc、gcc、sun studio 和 HP 的 aCC
是否有一个独立的工具可以完成相同的工作?
#include "Foo.h"
...//more includes
class Bar {
.......
private:
Foo* m_foo;
};
I've got a largeish codebase that's been around for a while and I'm trying to tidy it up a bit by refactoring it. One thing I'd like to do is find all the headers where I could forward declare members, instead of including the entire header file.
This is a fairly labour intensive process and I'm looking for a tool that could help me figure out which headers have members that could be forward declared.
Is there a compiler setting that could emit a warning or suggestion that the following code could use a forward declaration? I'm using the following compilers icc, gcc, sun studio and HP's aCC
Is there a standalone tool that could do the same job?
#include "Foo.h"
...//more includes
class Bar {
.......
private:
Foo* m_foo;
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
任何涉及 C++ 精确分析的事情本质上都需要在某个地方有一个完整的 C++ 前端(否则你不会得到答案,或者它们会是错误的,当你有“大型”应用程序时,这会很糟糕)。这里没有太多实用的答案。
已经提到的是 GCCXML 是一个 GCC 派生包,因此它具有必需的 C++ 前端。它生成 XML,因此它将生成大量输出,您必须读回这些输出以形成另一个答案中建议的“内存数据结构”。不幸的是,GCCXML 已经构建了该内存数据结构,然后将其导出为 XML,并迫使您再次构建它。当然,您可以只使用 GCC,它构建内存中的数据结构,但是您必须将 GCC 改造为您想要的,并且它真的非常想要成为一个编译器。这意味着您将面临一场斗争,让其屈服于您的意愿(并解释了为什么 GCCXML 存在:大多数人不希望这场斗争)。
没有提到的是 Edison Design Group C++ (EDG) 前端,它直接在内存数据结构中构建该前端。它是一个前端;您必须自己完成所有分析工作,但您的任务可能很简单,因此并不难。
我知道的最后一个解决方案是我的:C++ FrontEnd for DMS。 DMS 是构建程序分析的基础,其 C++ 前端是 C++ 的完整前端(例如,执行 GCC 和 Edison 前端所做的所有操作:解析、树构建、名称/类型解析)。您必须像针对 GCCXML 和 EDG 那样,通过遍历 DMS 生成的“内存中”数据结构来编写特殊分析代码。
真正不同的是,DMS 可用于通过更新内存数据结构中的源代码来实际修改源代码,并从这些内存结构(包括原始注释)重新生成可编译代码。
Anything involving the precise analysis of C++ requires essentially an entire C++ front end somewhere (otherwise you won't get answers, or they'll be wrong, and that works badly when you have "largish" applications). There aren't many practical answers available here.
Already mentioned is GCCXML is a GCC-derived package, so it has the requisite C++ front end. It produces XML, thus it will produce a LOT of output that you'll have to read back in to form "the in memory data structure" suggested in another answer. Its unfortunate that GCCXML builds that memory data structure already, then exports it as XML, and forces you to build it again. Of course, you could just use GCC, which builds the in memory data structure, but then you have to hack GCC to be what you want, and it really, really wants to be a compiler. That means you'll have a fight on your hands to bend it to your will (and explains why GCCXML exists: most people don't want that fight).
Not mentioned is the Edison Design Group C++ (EDG) front end, which builds that in memory data structure directly. It is a front end; you'll have to do all the analysis stuff yourself but your task may be simple enough so that isn't hard.
The last solution I know is mine: C++ FrontEnd for DMS. DMS is foundation for building program analysis, and its C++ FrontEnd is a complete Front end for C++ (e.g., does everything the GCC and Edison front ends do: parsing, tree building, name/type resolution). And you'll have to code your special analysis much the way you would for GCCXML and EDG by walking over the "in memory" datastructures produced by DMS.
What is really different is that DMS could then be used to actually modify your source code by updating those in memory data structures, and regenerate compilable code from those memory structures, including the original comments.
我不确定您是否会找到任何开箱即用的东西,但一种选择是使用 Python 和 pygccxml 包可以为您做一些分析。
基本上,您可以使用 pygccxml 构建源代码的内存图表,然后使用它来查询您的类和函数,以找出它们实际需要包含的功能。
因此,例如,您可以询问每个类,给我指针类型的成员:然后对于每个指针类型,您可以计算出接口中是否使用了该类的真实实例(非指针),如果不是,您可以计算出可以将其标记为前向声明的候选者。
缺点是脚本需要一些时间才能正确,因此成本可能超过收益,但这至少是一个有趣的练习。如果你有一些有用的东西,你可以将你的代码发布到 Github,也许其他人会发现它有用。
I'm not sure you'll find anything that does this out-of-the box, but one option would be to write a script using Python and the pygccxml package that could do some of this analysis for you.
Basically you'd use pygccxml to build an in-memory graph of your source code, then use it to query your classes and functions to find out what they actually need to include to function.
So for example you could ask each class, give me the members that are pointer types: then for each of those pointer types you could work out if a real instance (non pointer) of the class was used in the interface, and if not you could mark it as a candidate for forward declaration.
The downside is that the script would take some time to get right so the cost might outweigh the benefits but it would be an interesting exercise at least. You could post your code to Github if you got something that worked and maybe others would find it useful.
你可以做的是用 -MM 调用 gcc 。这将生成 Make 可以读取的依赖文件。您可以解析它们(使用 perl 或其他东西)来确定需要哪些包含以及哪些可以用前向声明替换,而不是使用它们。
What you could do is call gcc with -MM. This will produce dependency files that Make can read. Instead of having make use them, you could parse them (with perl, or something) to determine which includes are needed and which could be replaced with forward declarations.