C ++中的内联函数

时间:2010-03-23 16:36:09

标签: c++ inline-functions

如果我们在类定义本身中定义一个成员函数,它是否必须以内联方式处理,或者它只是对编译器的一个请求,它可以忽略。

7 个答案:

答案 0 :(得分:19)

是的,在类体内定义的函数是隐式inline

(与声明为inline的其他函数一样,它并不意味着编译器必须在调用函数的位置执行内联扩展,它只是允许“一个定义规则”的允许松弛,组合要求必须在使用该功能的所有翻译单元中包含定义。)

答案 1 :(得分:5)

正如其他人所说,类内定义的方法是内联自动请求的。 了解原因很有用。

假设不是。您必须为这样的函数生成代码,并且在调用它的任何地方,跳转到子例程指令都必须通过链接器引用该位置。

class A {
public:
  void f() { ... your code ... }
};

每次看到此代码时,如果它不是内联的,编译器只能假定它必须生成,因此它会生成一个符号。假设它是这样的:

A__f_v:

如果该符号是全局符号,那么如果您碰巧在不同模块中多次包含此类代码,则在链接时会出现多重定义的符号错误。所以它不可能是全球性的。相反,它是本地文件。

想象一下,您将上述头文件包含在许多模块中。在每一个中,它将生成该代码的本地副本。哪个比完全没有编译好,但是当你真的只需要一个代码时,你会获得多个代码副本。

这导致了以下结论:如果你的编译器不打算内联函数,那么你最好在某处声明它,而不是要求它内联。

不幸的是,内联和不内联是不可移植的。它由编译器编写者定义。一个好的经验法则是总是让每一个衬里,特别是所有自己只是调用函数的函数,内联,当您消除开销时。低于三行线性代码的任何东西几乎都可以。但是如果你在代码中有一个循环,那么问题是编译器是否会允许它内联,更重要的是,即使你做了你想做的事情,你会看到多少好处。

考虑这个内联代码:

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

它不仅与源代码中的原型一样小,而且内联代码生成的汇编语言小于对例程的调用。所以这段代码更小,更快。

而且,如果你碰巧传入常数:

int c= add(5,4);

它在编译时解决,没有代码。

在gcc中,我最近注意到即使我没有内联代码,如果它是文件的本地代码,它们也会偷偷地内联它。只有当我在一个单独的源模块中声明该函数时,它们才会优化掉该调用。

另一方面,假设您在1000行代码上请求内联。即使你的编译器足够愚蠢,你唯一能节省的就是调用本身,而且每次调用它时,编译器必须粘贴所有代码。如果你调用该代码n次,你的代码增长了例程* n的大小。所以任何大于10行的东西都不值得内联,除了特殊情况,它只被称为非常少的次数。其中一个例子可能是私有方法,只有另外两个人调用。

如果您请求内联包含循环的方法,那么只有经常执行少量循环才有意义。但考虑一个迭代一百万次的循环。即使代码是内联的,在通话中花费的时间百分比也很小。因此,如果你有方法在其中包含循环,这往往更大,那些值得从头文件中删除,因为它们a)将倾向于被编译器内联拒绝,并且b)即使它们被内联,通常也是如此不会提供任何好处

答案 2 :(得分:3)

编译器必须将其视为内联请求 - 它可以忽略。有一些习惯用于定义标题中的某些函数(例如空虚拟析构函数)和一些必要的标题定义(模板函数),但除此之外,请参阅GotW #33以获取更多信息。

有些人已经注意到编译器甚至可能内联你从未问过的函数,但我不确定这是否会破坏请求内联函数的目的。

答案 3 :(得分:3)

确实内联 - 但编译器可以忽略任何内联请求。

答案 4 :(得分:2)

请求编译器忽略它。

答案 5 :(得分:2)

2003 ISO C ++标准说

  

7.1.2 / 2带内联的函数声明(8.3.5,9.3,11.4)   说明符声明内联   功能。内联说明符   表示执行情况   内联替换函数   在呼叫点的身体是   优于通常的函数调用
  机制。实现不是   需要执行此内联
  在通话点替换;   然而,即使这个内联
  替换被省略,另一个   内联函数的规则已定义   7.1.2仍应受到尊重。

     

7.1.2 / 3在类定义中定义的函数是内联的   功能。内联说明符应   不出现在块范围函数中   声明。

     

7.1.2 / 4应在每个翻译单元中定义内联函数   使用和应有的   每一个都有完全相同的定义   案例(3.2)。 [注意:打电话给   可能遇到内联函数   在它的定义出现之前   翻译单位。 ]如果一个功能   声明了外部链接   它在一个翻译单元中内联   应全部在线声明   它所在的翻译单位   出现;无需诊断。一个   内联函数与外部   联系人应具有相同的地址   所有翻译单位。静止的   外部内联中的局部变量
  功能总是指相同的   宾语。中的字符串文字   extern内联函数是一样的   不同翻译中的对象
  单元。

答案 6 :(得分:1)

有两件事不应该混为一谈:

  1. 如何将函数标记为内联:在签名前面使用内联定义或在声明点定义;
  2. 编译器将如何处理此类内联标记:无论您如何将该函数标记为内联,它都将被视为编译器的请求。