C++ - 如果我们应该在 header 中定义方法,那么 inline 关键字有什么用?

C++ - What is the use of inline keyword if we should define method in header?

根据答案here,只需要在header文件中定义方法以使其内联。所以我的问题是,为什么有 inline 关键字?

简答。这不是必需的。编译器通常会忽略 inline 关键字。 其他问题中已经给出了更全面的答案,更不用说您链接的问题中的第二个答案了。

例如,如果要在header中定义一个自由函数(不是class的成员函数),则需要声明它inline,否则将其包含在多个翻译单元中会导致 ODR 违规。

通常的做法是在header中声明函数,在单独编译的.cpp文件中定义。但是,在 header 中将其定义为 inline 函数允许包含它的每个翻译单元都有其可用的定义,这使得该函数更容易实际内联;如果函数被大量使用,这很重要。

inline 关键字的历史原因是旧的 C 编译器无法像现代 C 和 C++ 编译器那样优化代码。因此,最初引入它是为了允许程序员指示对 inline 函数的偏好(有效地将函数 body 直接插入调用者,这避免了与函数调用相关的开销)。由于无法保证编译器 可以 内联函数(例如,某些编译器只能内联某些类型的函数),因此 inline 关键字被用作提示而不是指令。

inline 的其他典型用法不是自由裁量的——如果一个函数在多个编译单元中定义(例如,因为包含 header 的 #included 不止一次)然后离开 inline 会导致违反一个定义规则(因此会导致未定义的行为)。 inline 是给编译器的一条指令(编译器可能会向链接器发出指令)以解决这种偶然违反 one-definition 规则的情况,并生成一个工作程序(例如,不会导致链接器抱怨多个定义)。

至于为什么仍然需要它,从功能上讲,预处理器只进行文本替换......例如用包含的 header.

的内容替换 #include 指令

让我们考虑两种情况。第一个有两个源文件(编译单元);

 #include "some_header"

   //some other functions needed by the program, not pertinent here

 #include "some_header"

 int main()
 {
      foo();
 }

其中 some_header 包含定义

  void foo() { /* whatever */ }

然而,第二种情况省略了 header 文件(是的,人们这样做了)并将第一个源文件作为

void foo() { /* whatever */ }

   //some other functions needed by the program, not pertinent here

第二个为;

 void foo() { /* whatever */ }

 int main()
 {
      foo();
 }

在这两种情况下,假设两个编译单元被编译并链接在一起。结果违反了一个定义规则(实际上,由于多重定义的符号,通常会导致链接器错误)。

根据当前的语言规则(具体来说,预处理器只进行文本替换),这两种情况需要在功能上完全等同。如果一种情况是打印值 42,那么另一种情况也应该如此。如果一个有未定义的行为(就像这里的情况一样),另一个也是如此。

但是,为了便于讨论,如果一个函数定义在 header 中,则需要神奇地内联该函数。这两种情况下的代码将不再等效。 header 文件版本将具有已定义的行为(不违反一个定义规则)而第二个将具有未定义的行为。

糟糕。我们刚刚打破了这两种情况的等价性。这可能看起来不多,但程序员实际上很难理解为什么一个版本链接而另一个版本不链接。他们将没有办法解决这个问题......除了将代码移动到 header 文件中。

这意味着,我们需要一些方法使这两个场景等效。这意味着代码中需要有一些东西使它们等价。输入 inline 关键字,并将其添加到 foo().

的定义前

现在,好吧,有人可能会争辩说预处理器应该做一些更智能的事情,即做的不仅仅是简单的文本替换。但是,现在你正处于湿滑的斜坡上。 C 和 C++ 标准确实(详细地)指定预处理器执行此操作。改变这一点会带来一连串的其他变化。不管这是个好主意(当然,有人提倡从 C++ 中完全消除预处理器),这是一个更大的变化,对语言和程序员(谁,它是否好或者不好,可以依赖于预处理器的行为)。