C ++隐含内联函数

时间:2012-11-14 08:36:43

标签: c++ inline

我在文档中读到了关于内联函数的说法。我的文档说:有两种类型的内联函数:implicity functionexplicity function

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的每个方法,我必须在课堂外声明,对吧?如果这是真的,我可以在类中实现一个方法而不需要内联函数。

谢谢:)

4 个答案:

答案 0 :(得分:7)

保证它不是内联的唯一方法是在编译时使其无法访问,例如,将其主体定义放入cpp文件而不是标题。

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

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

为什么需要禁用内联?编译器通常知道更好...如果它是出于调试目的,只需禁用优化,或者至少是函数内联。您甚至可以使用编译指示在单个文件中执行此操作。无论如何,通常应该避免调试发布版本,当然有时候无法避免它。

答案 1 :(得分:5)

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-functions 作为O3的一部分

      

    考虑所有内联函数,即使它们未被声明   排队。编译器启发式地决定哪些函数值得   以这种方式集成。
    如果对给定函数的所有调用都是   集成,并且函数声明为static,然后函数是   通常不会以汇编代码的形式输出。

  • -finline-functions-called-once 作为O1的一部分

      

    考虑所有调用一次的静态函数,以便内联到它们中   即使他们没有内联标记,也会调用者。如果打电话给定   函数被集成,然后该函数不作为汇编器输出   代码本身。

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

  

除了标有的内容之外,不要扩展任何内联函数   always_inline属性。这是未优化时的默认值   单个函数可以通过标记来免除内联   noinline属性。

答案 2 :(得分:3)

是的,类定义中的所有方法定义都是隐式inline

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

答案 3 :(得分:2)

首先,将inline关键字用于函数是完全合法的 在一个类中定义:

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

此处的关键字是多余的,但并非违法。

其次,虽然inline关键字意味着提示 编译器,它所允许的唯一正式的,必需的含义 函数的多个定义,不会导致未定义的行为 由于违反了一个定义规则。编译器确实忽略了 在某些情况下:

  • 大多数编译器会在为调试设计的选项时忽略它 给定(或优化被关闭),并且实际上不会内联 任何东西。

  • 最佳编译器在最大化优化时会完全忽略它 被打开;函数是否内联将取决于唯一性 关于编译器对代码和分析数据的分析,以及给定的 函数将在一个位置内联(它位于一个位置的中间) 紧密的循环),而不是另一个。 (与其他一些海报不同 已经说过,即使呼叫站点和功能定义也会发生这种情况 有两个不同的翻译单位。)

在这两个极端之间,很多编译器做 模块间分析,至少在某种程度上 打开优化,"至少在大多数情况下接受提示" 例如,递归内联函数几乎肯定会 如果编译器无法确定深度,则生成内联 在编译时递归。大多数编译器都无法使用 如果无法确定实际的内联生成虚函数 有局部静态分析的对象的类型,虽然有些 最好的,给定的分析器输出,揭示了一个特定的 重载将在99%的时间被调用,可能会生成if,和 内联一个案例。

通常,您希望在头文件中尽可能少地定义, 所以对于"导出"类,你不会使用inline(显式或隐式) 除非探查者说这是绝对必要的。对于本地课程, 在源文件中定义,无论你是谁,它都是一种风格问题 定义类定义中的函数与否(它可能或可能 关于编译器是否将它们内联 - 就像我一样没有区别 说,通常的调试选项,大多数编译器不会内联 任何东西)。