用C++编写头文件中的函数定义

Nav*_*K N 61 c++ performance header-files

我有一个有很多小功能的课.通过小函数,我的意思是不执行任何处理但仅返回文字值的函数.就像是:

string Foo::method() const{
    return "A";
}
Run Code Online (Sandbox Code Playgroud)

我创建了一个头文件"Foo.h"和源文件"Foo.cpp".但由于函数非常小,我正在考虑将它放在头文件中.我有以下问题:

  1. 如果我将这些函数定义放在头文件中,是否有任何性能或其他问题?我会有很多这样的功能.
  2. 我的理解是编译完成后,编译器将扩​​展头文件并将其放在包含它的位置.那是对的吗?

Joh*_*itb 67

如果函数很小(你经常改变它的可能性很低),并且如果函数可以放入标题而不包括无数的其他标题(因为你的函数依赖于它们),那么这样做是完全有效的.如果你声明它们是extern inline,那么编译器需要为每个编译单元提供相同的地址:

headera.h:

inline string method() {
    return something;
}
Run Code Online (Sandbox Code Playgroud)

成员函数是隐式内联的,前提是它们是在类中定义的.同样的事情对他们来说也是如此:如果他们可以毫不费力地加入标题,你确实可以这样做.

因为函数的代码被放入标题并且可见,所以编译器能够内联调用它们,也就是说,将函数的代码直接放在调用站点上(不是因为你把它放在它之前,而是更多因为编译器决定了这种方式.仅内联是对编译器的暗示.这可以带来性能提升,因为编译器现在可以看到参数匹配函数本地变量的位置,以及参数不会相互别名的地方 - 最后但并非最不重要的是,不再需要函数框架分配.

我的理解是编译完成后,编译器将扩​​展头文件并将其放在包含它的位置.那是对的吗?

对,那是正确的.该函数将在包含其标题的每个位置定义.编译器将关心通过消除其他程序将其中只有一个实例放入生成的程序中.


Fer*_*cio 12

根据您的编译器及其设置,它可能会执行以下任何操作:

  • 它可能会忽略inline关键字(它只是对编译器的提示,而不是命令)并生成独立的函数.如果您的函数超出了编译器相关的复杂度阈值,它可能会这样做.例如,太多嵌套循环.
  • 它可能决定您的独立功能是内联扩展的良好候选者.

在许多情况下,编译器处于更好的位置来确定函数是否应该内联,所以没有必要再次猜测它.我喜欢在类有许多小函数时使用隐式内联,因为它很方便在类中实现.对于较大的功能,这不太适用.

要记住的另一件事是,如果你在DLL /共享库中导出一个类(不是一个好主意恕我直言,但人们仍然这样做)你需要非常小心内联函数.如果构建DLL的编译器决定一个函数应该内联,你有几个潜在的问题:

  1. 使用DLL构建程序的编译器可能决定不内联函数,因此它将生成对不存在的函数的符号引用,并且DLL将不会加载.
  2. 如果更新DLL并更改内联函数,则客户端程序仍将使用该函数的旧版本,因为该函数已内联到客户端代码中.

  • 虚函数不能内联,需要通过vtable中的指针引用它们.我从来没有尝试过,但编译器应该忽略内联或抱怨它. (2认同)

Qub*_*euc 5

由于头文件中的实现是隐式内联的,因此性能会有所提高。正如您提到的,您的函数很小,恕我直言,内联操作对您非常有益。

你所说的关于编译器的说法也是正确的。对于编译器来说,除了内联之外,头文件或.cpp文件中的代码没有任何区别。