CB *_*ley 19
是的,隐式地在类体内定义的函数inline.
(与声明的其他函数一样,inline它并不意味着编译器必须在调用函数的地方执行内联扩展,它只是允许"一个定义规则"的允许放宽,并结合定义必须是包含在使用该功能的所有翻译单元中.)
如其他人所述,类内定义的方法是内联自动请求的.了解原因很有用.
假设它不是.您必须为这样的函数生成代码,并且在调用它的任何地方,跳转到子例程指令都必须通过链接器引用该位置.
class A {
public:
void f() { ... your code ... }
};
Run Code Online (Sandbox Code Playgroud)
每次看到这段代码时,如果它不是内联的,编译器只能假设它必须被生成,所以它会生成一个符号.假设它是这样的:
A__f_v:
如果该符号是全局符号,那么如果您碰巧在不同的模块中多次包含此类代码,则在链接时会出现多重定义的符号错误.所以它不可能是全球性的.相反,它是本地文件.
想象一下,您将上述头文件包含在许多模块中.在每一个中,它将生成该代码的本地副本.哪个比完全没有编译要好,但是当你真的只需要一个代码时,你会获得多个代码副本.
这导致了以下结论:如果您的编译器不打算内联函数,那么最好不要在某处声明它,而不是要求它内联.
不幸的是,内联和不内联是不可移植的.它由编译器编写者定义.一个好的经验法则是总是让每一个衬里,特别是所有自己只是调用函数的函数,内联,当您消除开销时.低于三行线性代码的任何东西几乎都可以.但是如果你在代码中有一个循环,那么问题是编译器是否会允许它内联,更重要的是,即使它做了你想要的,你会看到多少好处.
考虑这个内联代码:
inline int add(int a, int b) { return a + b; }
Run Code Online (Sandbox Code Playgroud)
它不仅与源代码中的原型一样小,而且内联代码生成的汇编语言小于对例程的调用.所以这段代码更小,更快.
并且,如果您碰巧传递常数:
int c= add(5,4);
Run Code Online (Sandbox Code Playgroud)
它在编译时解决,没有代码.
在gcc中,我最近注意到即使我没有内联代码,如果它是文件的本地代码,它们也会偷偷地内联它.只有当我在一个单独的源模块中声明该函数时,它们才会优化掉调用.
另一方面,假设您在1000行代码上请求内联.即使你的编译器足够愚蠢,你唯一能节省的就是调用本身,而且每次调用它时,编译器必须粘贴所有代码.如果你调用该代码n次,你的代码增长了例程*n的大小.所以任何大于10行的东西都不值得内联,除了特殊情况,它只被称为非常少的次数.这方面的一个例子可能是由另外两个人调用的私有方法.
如果您请求内联一个包含循环的方法,那么只有它经常执行很少次才有意义.但考虑一个迭代一百万次的循环.即使代码是内联的,在通话中花费的时间百分比也很小.因此,如果你有方法在其中包含循环,往往更大,那些值得从头文件中删除,因为它们a)将倾向于被编译器内联拒绝,并且b)即使它们被内联,通常也是如此不会提供任何好处