内联关键字与标题定义

时间:2012-04-11 09:20:54

标签: c++ optimization inline

在函数之前使用inline关键字和在标题中声明整个函数之间的区别是什么?

所以...

int whatever() { return 4; }

VS

·H:

inline int whatever();

的.cpp:

inline int myClass::whatever()
{
    return 4;
}

就此而言,这是做什么的:

inline int whatever() { return 4; }

5 个答案:

答案 0 :(得分:29)

有几个方面:

<强>语言

  • 当一个函数用inline关键字标记时,它的定义应该在TU中可用,或者程序格式错误。
  • 在类定义中定义的任何函数都隐式标记为inline
  • 标记为inline(隐式或显式)的函数可以在多个TU中定义(关于ODR),而常规函数则不是这样。
  • 模板功能(不完全专业化)获得与inline个相同的处理。

编译器行为

  • 标记为inline的函数将在每个目标文件中作为弱符号发出,这可能会增加它们的大小(查找模板膨胀)。
  • 编译器实际内联调用(即,在使用点复制/粘贴代码而不是执行常规函数调用)完全由编译器自行决定。关键字的存在可能会或不会影响决策,但最多只能是提示

链接器行为

  • 弱符号合并在一起,在最终库中出现一次。一个好的链接器可以检查多个定义是否同意,但这不是必需的。

答案 1 :(得分:10)

没有 inline,如果函数在命名空间或全局范围内声明,则可能最终会出现多个导出符号(导致链接器错误) )。

但是,对于一个类(如您的示例所示),大多数编译器隐式将该方法声明为内联(-fno-default-inline将在GCC上禁用该默认值。)

如果将函数声明为内联函数,编译器可能希望在转换中看到它的定义。因此,您应该在定义可见的时候保留它。

在更高级别:更多翻译经常可以看到类声明中的定义。这可以带来更好的优化,并且可以增加编译时间。

除非手动优化和快速编译都很重要,否则最近在类声明中使用关键字是不常见的。

答案 2 :(得分:9)

inline的目的是允许在多个翻译单元中定义函数,这对于某些编译器能够在任何使用它的地方内联它是必要的。它应该在头文件中定义函数时使用,尽管在定义模板或类定义中的函数时可以省略它。

在没有inline的标题中定义它是一个非常糟糕的主意;如果你包含多个翻译单元的标题,那么你就打破了一个定义规则;您的代码可能不会链接,如果有,可能会显示未定义的行为。

inline的标题中声明它但在源文件中定义它也是一个非常糟糕的主意;该定义必须在使用它的任何翻译单元中可用,但通过在源文件中定义它,它只能在一个翻译单元中使用。如果另一个源文件包含标题并尝试调用该函数,则您的程序无效。

答案 3 :(得分:3)

此问题解释了很多内联函数What does __inline__ mean ?(即使它是关于内联关键字。)

基本上,它与标题无关。在标题中声明整个函数只会更改函数源所在的源文件.Inline关键字会修改生成的编译函数的放置位置 - 在它自己的位置,以便每次调用将去那里,或代替每次通话(更好的表现)。但是,编译器有时会选择为自己内联的函数或方法,关键字只是编译器的建议。即使是内联未指定的函数,编译器也可以选择内联函数,如果这样可以提供更好的性能。

答案 4 :(得分:1)

如果要将多个对象链接到可执行文件中,通常应该只有一个对象包含该函数的定义。对于int whatever() { return 4; } - 用于生成对象的任何翻译单元将包含whatever函数的定义(即可执行代码)。链接器将不知道将哪个指向呼叫者。如果提供了inline,则可执行代码可能会或可能不会在调用站点内联,但如果不是,则允许链接器假定所有定义都相同,并且任意选​​择一个以将调用者指向。如果不知何故定义不一样,那么它被认为是你的错,你会得到未定义的行为。要使用inline,在编译调用时必须知道定义,因此,如果所有调用者恰好在以后的所有调用者中,那么将内联声明放在标题中以及内联定义放在.cpp文件中的想法将起作用。相同的.cpp文件 - 通常它已经坏了,你希望(名义上)内联函数的定义出现在声明它的标题中(或者没有事先声明就有一个单独的定义)。