【问题标题】:How much is reduction in compile time if move very simple definition of function to .cpp?如果将非常简单的函数定义移至 .cpp,编译时间会减少多少?
【发布时间】:2016-12-22 09:46:23
【问题描述】:

一些同事(比我聪明)告诉我,在某些情况下,将实现(定义)移到头文件之外可以减少编译时间 - 在大多数情况下我应该这样做。

经过大量的重构,我相信是真的。

现在我也计划移动非常简单的功能的实现。 (.h -> .cpp)

void f(int index){
    return database[index*2];  //<--- contain trivial algorithm like this
}

问题

决定收益多少的因素有哪些?

更具体地说:-

  1. 用于编译的时间量是否取决于

    • 字符数(不包括评论)我已移至 .cpp 或 ...

    • 复杂度(这里不是指 O(n))函数或算法的...

    • 还有别的吗?

  2. 我应该将这些简单函数的定义移至 .cpp 吗?
    (只关心性能和编译时间,不关心可维护性和可读性)

编辑:详细示例

考虑一下这段代码。

B.h :-

class B{
    public: static void fb(){  
        //some complex code (e.g. 1000 lines)
    }
};

C.h :-

#include "B.h"
class C{
    static void fc();
};

C.cpp 包含fc()的实现

D.h :-

#include "B.h"
class D{
    static void fd();
};

D.cpp包含fd()的实现

在移动fb 的定义之前,编译器必须为C.cppD.cpp 编译B.h 的大代码。

fb的定义移动到b.cpp后,我认为C.cppD.cpp会更容易编译。

【问题讨论】:

  • 真正的编译器性能提升在于不重新编译已经编译的模块

标签: c++


【解决方案1】:

决定收益多少的因素有哪些?

减少编译时间的主要因素取决于有多少其他翻译单元包含该标头和内联代码。你提到的其他因素只是无关紧要。

如果您更改定义中的某些内容,则需要重新编译更多文件,而不是仅更改单个 .cpp 文件中的定义。

  1. 我应该将这些简单函数的定义移至 .cpp 吗? (只关心性能和编译时间,不关心可维护性或可读性)

不,我上面说的是非平凡的东西。如果你有这么简单的函数定义,而且以后不太可能改变,你可以把它放在头文件中。

【讨论】:

  • 对于 such 一个微不足道的功能,我会将其保留在标题中。您不太可能在那里进行更改。同样,容器中的“size”方法应该是内联的。
  • @Martin 同意。对于不太可能改变的琐碎事情,我也会这样做。我试图回答 OP 对整体影响以及他们的同事所指(最有可能)的困惑。
  • 我认为在详细示例(我刚刚添加)的情况下(编译器)有一些性能提升。是不是觉得好处不大?我错过了什么吗?
  • @javaLover :在您的详细示例中,是的,如果在 b.cpp 中定义了 B::fb,则从头开始干净重建会更快,因为 B::fb 只需解析一次而不是两次。但是, 的区别在于,当您更改 B::fb 时,您将需要重新编译 b.cpp,而不是重新编译 c.cpp 和 d.cpp。 (而且您很可能会更改 1000 行函数)。
  • @javaLover 补充马丁斯的评论。对于琐碎的功能,从头开始构建的效果将是最小的。
【解决方案2】:

答案可以简单,也可以不那么简单。

简单回答:

  • 将非平凡函数的实现放在源文件中,这样做有很多好处,而不仅仅是编译时间。

  • 将琐碎函数的实现留在头文件中,将非成员函数内联,编译时间不会有明显差异,还有更好的优化可能性。

不那么简单:

  • 将重要的函数放入源文件是专门完成的,这样头文件就像代码的接口一样,更具可读性,不必包含实现所需的所有包含,可以防止相互循环问题,最重要的是有更好的编译时间。

  • 将琐碎的函数放在头文件中可以让编译器在编译时(而不是链接时)进行更好的优化,因为它在调用点知道函数的作用,因此它知道何时内联更好并重新排序代码(有关链接时间优化,请参阅here)。

  • 模板仍应始终位于头文件中。对于一些复杂的函数,非模板部分可能会被分解并放入源文件中,但这可能很繁琐。

  • 出于封装原因,最好在源文件中完整声明辅助函数和辅助类。

  • 使用 pimpl-constructs 时,琐碎的委托函数必须在源文件中,因为只有在源文件中,pimpl 才完全已知。

所以最终对代码进行排序可以缩短编译时间,但这不应该是主要原因。

【讨论】:

  • “模板仍应始终位于头文件中。” 它们必须出现在头文件中。
  • @πάντα ῥεῖ 我依稀记得它可以通过一些重大困难移出。 (已知 T)我不记得具体怎么做,可能是……因为太不方便了。
  • "... 可以缩短编译时间,但这不应该是主要原因" +1。编译时间几乎不应该成为选择一种编写代码的方式而不是另一种编写代码的原因。
【解决方案3】:

如果你调用这个主体在 .h 中的函数,它会引用你的 #include 来找到它,因为 #include 只给出一个引用。

如果你的函数体在 .cpp 中,编译器会更容易

我建议你检查一下。它也帮助了我。

What techniques can be used to speed up C++ compilation times?

【讨论】:

  • reference 是什么意思?声明?
  • 是的,这是一个很好的链接,它也帮助了我。您能否提供一些参考/链接/证据/文档来支持“如果您的函数的主体在 .cpp 中,编译器会更容易”这一说法?
  • @javaLover 他们的意思可能与 Martin 所说的相同。编译器只需要解析一次代码。
  • @πάνταῥεῖ 我的意思是头文件中的代码将被包含 - 引用的次数与您的 .cpp 文件的数量一样多
猜你喜欢
  • 2015-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-03
  • 1970-01-01
  • 2022-08-17
  • 1970-01-01
相关资源
最近更新 更多