2012-11-14 44 views
3

我已经在我的文档中看过关于内联函数的内容。我的文档说:有两种内联函数:implicity functionexplicity functionC++隐含内联函数

Explicity function:在函数之前使用inline关键字,并且在类之外使用。例如:

inline int Math::add(int a, int b){ return a + b; } 

Implicity function:班级内的每种方法都是隐含的。例如:

class Math { 
    int add(int a, int b) { return a + b;} // implicity inline function 
}; 

所以,如果这是真的,那么,我不希望使用inline每一个方法,我必须声明类以外的,对不对?如果这是真的,我可以在类中实现一个方法,并且不需要内联函数。

谢谢:)

+5

如果在类中定义了*,则它隐式地内联。 – Mysticial

回答

7

保证它不是内联的唯一方法是在编译时将其设置为不可访问,例如,将其主体定义放入cpp文件而不是头中。

更新:一位评论者说,即使将函数体放入不同的编译单元也不能保证有帮助。他绝对是对​​的。通常它是有帮助的,但是一些编译器仍然可以内联函数。 因此,没有可靠的方法来禁用不依赖于编译器的内联。

所有的内联只是一个优化问题。如果开启了适当的优化,通过编写内联关键字,您可以告诉编译器,您推荐内联函数。你既不能强制编译器内联一个函数,也不能强制编译器不内联它。对于某些编译器,例如VC++有办法这样做(__declspec(noinline)),但它们都是依赖于编译器的。

为什么你需要禁用内联?编译器通常会更好地了解...如果是用于调试目的,只需禁用优化,或至少功能内联。你甚至可以在一个文件中使用编译指示来做到这一点。无论如何,通常应该避免调试发行版,尽管有时不可能避免它。

+2

有没有办法来保证函数是否内联。语言标准定义了可观察行为的正确性,函数是否在线或不对可观察行为没有影响。 (有些编译器会在不同的翻译单元中定义内联函数,根据分析器输出来选择哪些内联函数。) –

+0

这是真的。编译器确实可以这样做,但通常他们不这样做。没办法强制他们。 – Ellioh

+0

另一方面......几乎我见过的每个编译器都有一个选项来完全关闭内联,以便于调试。 –

3

是的,这是真的,一个类定义内部定义所有方法隐含inline

请注意,inline并不意味着编译器会实际将其内联在代码中。如果你希望它不是内联的,只需在实现文件中分离实现。

+0

将函数定义放入单独的文件中并不一定会防止内联;有些编译器会根据调用函数的频率进行模块间分析和内联。 –

4

C++ standard阅读,如何的“隐式内联函数”被定义:

的成员函数可以在它的类定义来定义(8.4),在 它是这种情况下,内联成员函数 (7.1.2),或者它可能是在其类定义之外定义的 ,如果它已经在其类定义中声明了但未定义的 。在类定义之外出现的成员函数 定义应在包含类定义的命名空间范围中出现 。除类别定义以外的成员 功能定义和 类别 类别的成员函数的显式特殊化和成员函数模板(14.7)出现在类别定义之外的 以外,不应重新声明成员函数。

而且编译器并不能保证它真的会执行替换:

一个函数的声明(8.3.5,9.3,11.4)与联说明 声明的内联函数。内联说明符向 实现指出,在 的调用点处函数体的内联替换优于通常的函数调用机制。 在调用点执行此联机替换 不需要实现;但是,即使省略了这种内联替换 ,仍然遵守由7.1.2定义的内联函数的其他规则 。

每隔功能将可能是“非内联”,但一旦你打开优化许多奇怪的事情可能发生,例如看看gcc - Optimize options

  • -finline-small-functions作为的一部分O2

    集成功能到其调用时,他们的身体比 预期功能小调用代码(所以程序的整体大小变得更小)。 编译器试探性地决定哪些函数足够简单,因此 值得以这种方式进行集成。这种内联适用于所有 函数,即使那些没有声明为内联的函数。

  • -finline-functionsO3

    的一部分考虑所有功能内联,即使它们不声明 内联。编译器试探性地决定以这种方式集成哪些函数值得 。
    如果对给定函数的所有调用都集成了 ,并且该函数被声明为静态函数,那么函数 通常不会以汇编代码的形式单独输出。

  • -finline-functions-called-onceO1

    的一部分考虑所有内联成,即使他们不在线标志着他们 呼叫者调用一次的静态函数。如果集成一个给定的功能 的函数,那么该函数本身不会作为汇编程序 代码输出。

而在另一方面,你可以告诉编译器不内联函数(-fno-inline):

不展开任何功能从那些标有 always_inline属性直列分开。这是未优化时的默认值。
单功能可以通过标记为 noinline属性来免除内联。

+0

对于内联无法保证 – billz

2

首先,这是完全合法的使用inline关键字一类中定义的函数 :

struct MyClass 
{ 
    inline int someFunctions() { return 42; } 
}; 

的关键字在这里是多余的,但并不违法。

其次,虽然inline关键字意味着是一个暗示, 编译器,只是形式上的,必需的意义,它已经是允许的功能 多个定义,而不会导致不确定的行为 因违反一个定义规则。和编译器都忽略 它在某些情况下:

  • 大多数编译器会忽略它,当设计调试选项给出 (或优化被关闭),并不会实际内嵌 什么。

  • 当开启最大优化 时,最好的编译器会完全忽略它;一个函数是否被内联取决于编译器对代码和分析数据的分析,并且一个给定的函数将被内联在一个位置上(它位于一个 紧密环的中间),而不是另一个。 (而不像什么 说一些其他的海报,发生这种情况即使调用点和函数定义 有两种不同的翻译单元。)

在这两个极端之间,有很多的编译器做不是做 模块之间的分析,并且至少当开启某种程度的优化时,至少大部分时间是“采取提示”。 例如,如果编译器在编译时无法确定递归的深度,则递归内联函数几乎可以肯定地产生而不是 。并且大多数编译器不能 内联生成一个虚拟函数,如果他们不能通过局部静态分析确定对象的实际类型 最好,给定的分析器输出显示一个特定的 过载将被调用99 %的时间,可能会生成一个if和 内联那一种情况。

一般情况下,你要尽可能少,除非剖析说,这是绝对必要的定义在头文件, 所以对于“出口”类,你不会使用inline(显性或隐性) 。对于在源文件中定义的本地类 ,更重要的是您是否在类定义中定义函数 (并且它可能或可能不会影响编译器将它们内联为—为I 表示,通常的调试选项,大多数编译器不会内联 任何东西)。