简体   繁体   English

前向声明如何节省编译时间?

[英]How does forward declaration save compile time?

If you read online then there is plenty of claims that in C++ if you use forward declaration then it saves your compile time.如果您在线阅读,那么在 C++ 中有很多声明,如果您使用前向声明,那么它可以节省您的编译时间。 The usual theory is that since #include means mere text replacement if I use forward declaration, then my compiler doesn't need to parse the header and possibly compile it, so it saves time.通常的理论是,如果我使用前向声明, #include意味着仅仅是文本替换,那么我的编译器不需要解析 header 并可能编译它,所以它节省了时间。 I found this claim hard to believe because consider I usually see code like this:我发现这种说法很难相信,因为考虑到我通常会看到这样的代码:

// B.h

class A;

class B {
public:
void doSomething(A& a);
}

In this case, yeah, we don't need to include Ah in Bh as we forward declared it, but the problem is that in B.cpp eventually, we need a full type A to use its methods and data members.在这种情况下,是的,我们不需要在Bh中包含Ah ,因为我们转发声明它,但问题是最终在B.cpp中,我们需要一个完整的类型A来使用它的方法和数据成员。 So I found in nearly all cases, we need to include Bh in B.cpp .所以我发现几乎在所有情况下,我们都需要在B.cpp中包含Bh

So how does forward declaration actually save compile time?那么前向声明实际上是如何节省编译时间的呢? I see people with benchmarks to prove that if they use forward declaration instead of #include s, the compile time actually goes down, so there must be something I do not understand here...我看到有人用基准来证明如果他们使用前向声明而不是#include s,编译时间实际上会下降,所以这里肯定有我不明白的东西......


I know saving compile time is not the sole purpose of forward declaration, I understand it has other purposes.我知道节省编译时间不是前向声明的唯一目的,我知道它还有其他目的。 I just want to understand why some people claim it can save compile time.我只是想了解为什么有些人声称它可以节省编译时间。

Compile times编译时间

the problem is that in B.cpp eventually, we need a full type A to use its methods and data members.问题是最终在B.cpp中,我们需要一个完整的类型A来使用它的方法和数据成员。

Yes, that is a typical pattern.是的,这是一个典型的模式。 Forward declare a class (eg A ) in a header (eg Bh ), then in the source code corresponding to that header ( B.cpp ), include the header for the forward-declared class ( Ah ). Forward declare a class (eg A ) in a header (eg Bh ), then in the source code corresponding to that header ( B.cpp ), include the header for the forward-declared class ( Ah ).

So I found in nearly all cases, we need to include Bh in B.cpp .所以我发现几乎在所有情况下,我们都需要在B.cpp中包含Bh

Correct, forward declarations do not save time when compiling the corresponding source code .正确的前向声明在编译相应的源代码时不会节省时间。 The savings come when compiling other source code that uses B .编译使用B的其他源代码时可以节省。 For example:例如:

other.cpp其他.cpp

#include "B.h"

// Do stuff with `B` objects.
// Make no use of `A` objects.

Assume this file does not need definitions from Ah .假设这个文件不需要Ah的定义。 This is where the savings come in. When compiling other.cpp , if Bh uses a forward declaration of A , there is no need to process Ah .这就是节省的地方。编译other.cpp时,如果Bh使用A的前向声明,则无需处理Ah Nor is there a need to process the headers that Ah itself includes, and so on.也不需要处理Ah本身包含的标头,等等。 Now multiply this effect by the number of files that include Bh , either directly or indirectly.现在将此效果乘以直接或间接包含Bh的文件数。

Note that there is a compounding effect here.请注意,这里有一个复合效应。 The number of "headers that Ah itself includes" and of "files that include Bh " would be the numbers before replacing any #include statements with forward declarations. Ah本身包含的标题”和“包含Bh的文件”的数量将是在用前向声明替换任何#include语句之前的数字。 (Once you start making these replacements, the numbers come down.) (一旦你开始进行这些替换,数字就会下降。)

How much of an effect?有多大的作用? Not as much as there used to be.没有以前那么多了。 Still, as long as we're talking theoretically, even the smallest savings is still a savings.尽管如此,只要我们在理论上谈论,即使是最小的储蓄仍然是储蓄。

Rebuild times重建时间

Instead of raw compile times (build everything), I think a better focus would be on rebuild times.而不是原始编译时间(构建所有内容),我认为更好地关注重建时间。 That is, the time it takes to compile just the files affected by a change you made.也就是说,仅编译受您所做更改影响的文件所需的时间。

Suppose there are ten files that rely on Bh but not on Ah .假设有十个文件依赖于Bh但不依赖于Ah If Bh were to include Ah , then those ten files would be affected by changes to Ah .如果Bh包含Ah ,那么这十个文件将受到Ah更改的影响。 If Bh were instead to forward declare A , then those files would not be affected by changes to Ah , reducing the time to rebuild after those changes.如果Bh改为转发声明A ,那么这些文件将不会受到Ah更改的影响,从而减少了这些更改后的重建时间。

Now suppose there is another class, call it B2 , that also has the option to forward declare A instead of including the header.现在假设还有另一个 class,称为B2 ,它还可以选择转发声明A而不是包括 header。 Maybe there are another ten files that depend on B2 but not on B and not on A .也许还有另外十个文件依赖于B2但不依赖于B而不是依赖于A Now there are a twenty files that do not need to be re-compiled after changes to A .现在有二十个文件在更改A后不需要重新编译。

But why stop there?但为什么要停在那里? Let's add B3 through B10 to the mix.让我们将B3B10添加到混合物中。 Now there are a hundred files that do not need to be re-compiled after changes to A .现在有一百个文件在更改A后不需要重新编译。

Add another layer.添加另一层。 Suppose there is a C.h that has the option to forward declare B instead of including Bh .假设有一个C.h可以选择转发声明B而不是包括Bh By using a forward declarations, changes to Ah no longer require re-compiling the ten files that use C.h .通过使用前向声明,对Ah的更改不再需要重新编译使用C.h的十个文件。 And, of course, we'll assume there are ten such files for each of B through B10 .而且,当然,我们假设BB10中的每一个都有十个这样的文件。 Now we're up to 10*10*10 files that do not need to be recompiled when Ah changes.现在我们最多有10*10*10文件,当Ah发生变化时不需要重新编译。

Takeaway带走

This is a simplified example to serve as a demonstration.这是一个简化的示例,用作演示。 The point is that there is a forest of dependency trees created by #include lines.关键是#include行创建了一个依赖树森林。 (The root of such a tree would be the header file of interest, and its children are the files that #include it.) Each leaf in one of these trees represents a file that must be compiled when changes occur in the header file of interest. (这样一棵树的根是感兴趣的 header 文件,它的子文件是#include它的文件。)其中一棵树中的每个叶子代表一个文件,当感兴趣的 header 文件发生更改时必须编译该文件. The number of leaves in a tree grows exponentially with the depth, so removing a branch (by replacing an #include with a forward declaration) can have a massive effect on rebuild time.树中的叶子数量随深度呈指数增长,因此删除分支(通过将#include替换为前向声明)会对重建时间产生巨大影响。 Or maybe a negligible effect.或者可能是微不足道的影响。 This is theory, not practice.这是理论,不是实践。


I should note that like the question, this answer focuses on compile times, not on the other factors to consider.我应该注意到,就像这个问题一样,这个答案侧重于编译时间,而不是其他要考虑的因素。 This is not supposed to be a comprehensive guide to the pros and cons of forward declarations, just an explanation for how they could save compilation time.这不应该是对前向声明的优缺点的全面指南,只是对它们如何节省编译时间的解释。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM