我有一个具有许多小功能的课程。通过小函数,我的意思是不执行任何处理但仅返回文字值的函数。类似的东西:
string Foo::method() const{
return "A";
}
我创建了一个头文件“Foo.h”和源文件“Foo.cpp”。但由于函数非常小,我正在考虑将它放在头文件中。我有以下问题:
答案 0 :(得分:66)
如果函数很小(你经常改变它的可能性很低),并且如果函数可以放入标题中而不包含无数其他标题(因为你的函数取决于它们),那么它是完全有效的这样做。如果你将它们声明为extern inline,那么编译器需要为每个编译单元提供相同的地址:
headera.h :
inline string method() {
return something;
}
成员函数是隐式内联的,前提是它们是在类中定义的。同样的事情对他们来说也是如此:如果他们可以毫不费力地加入标题,你确实可以这样做。
因为函数的代码被放入标题并且可见,所以编译器能够内联调用它们,即将函数的代码直接放在调用站点上(不是因为你在它之前放入内联函数)但更多的是因为编译器决定了这种方式。仅内联是对编译器的暗示。这可以带来性能提升,因为编译器现在可以看到参数匹配函数本地变量的位置,以及参数不会相互别名的地方 - 最后但并非最不重要的是,不再需要函数框架分配。
我的理解是编译完成后,编译器会扩展头文件并将其放在包含它的位置。这是对的吗?
是的,这是正确的。该函数将在包含其标题的每个位置定义。编译器将关心通过消除其他程序将其中只有一个实例放入生成的程序中。
答案 1 :(得分:12)
根据您的编译器及其设置,它可能会执行以下任何操作:
在许多情况下,编译器处于一个更好的位置来确定函数是否应该内联,所以没有必要再次猜测它。我喜欢在类有许多小函数时使用隐式内联,因为它很方便在类中实现。对于较大的功能,这不太适用。
要记住的另一件事是,如果要在DLL /共享库中导出类(不是一个好主意恕我直言,但人们仍然这样做),您需要非常小心内联函数。如果构建DLL的编译器决定函数应该内联,那么你有几个潜在的问题:
答案 2 :(得分:4)
性能会有所提高,因为头文件中的实现是隐式内联的。正如您所提到的,您的功能很小,内联操作对您来说非常有用恕我直言。
你对编译器的看法也是如此。除了内联文件或.cpp
文件中的代码之外,编译器没有区别。
答案 3 :(得分:2)
如果您的功能如此简单,请将它们内联,并且无论如何您都必须将它们粘贴在头文件中。除此之外,任何惯例都只是 - 惯例。
是的,编译器确实扩展了遇到#include语句的头文件。
答案 4 :(得分:2)
这取决于适用于您案例的编码标准,但是:
没有循环和其他任何东西的小函数应该内联以获得更好的性能(但稍微大一点的代码 - 对于某些受约束或嵌入式应用程序很重要)。
如果你在标题中有函数的主体,你将默认使用内联(d)(这在速度方面是一件好事)。
在编译器创建目标文件之前,调用预处理器(gcc的-E选项),并将结果发送给编译器,编译器从代码中创建对象。
所以简短的答案是:
- 在标题中声明函数有利于速度(但不适用于空间) -
答案 5 :(得分:1)
如果你这样做,C ++不会抱怨,但一般来说,你不应该抱怨。
当您#include一个文件时,包含文件的整个内容将被插入到包含的位置。这意味着您在标题中放置的任何定义都会被复制到包含该标题的每个文件中。
对于小型项目,这不太可能是一个问题。但是对于较大的项目,这可能会使编译需要更长的时间(因为每次遇到相同的代码时都会重新编译),并且可能会大大增加可执行文件的大小。如果对代码文件中的定义进行更改,则只需重新编译该.cpp文件。如果对头文件中的定义进行更改,则需要重新编译包含头的每个代码文件。一个小的改动可能导致您必须重新编译整个项目!
有时会对不太可能改变的琐碎函数进行例外处理(例如,函数定义是一行)。
来源:http://archive.li/ACYlo(有关learncpp.com的第1.9章的上一版本)
答案 6 :(得分:0)
您应该使用内联函数。阅读此Inline Functions以获得更好的理解和所涉及的权衡。