C ++ - 如果我们应该在头文件中定义方法,那么使用内联关键字有什么用?

时间:2016-11-02 06:27:59

标签: c++ inline keyword

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

3 个答案:

答案 0 :(得分:2)

例如,如果要在标题内定义自由函数(不是类的成员函数),则需要将其声明为inline,否则将其包含在多个翻译单元中将导致ODR冲突。

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

答案 1 :(得分:0)

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

inline的另一个典型用法并不是随意的 - 如果在多个编译单元中定义了一个函数(例如因为包含的标题是#include d不止一次),那么就离开{{1导致违反一个定义规则(因此在未定义的行为中)。 inline是对编译器的指令(反过来可能向链接器发出指令)来解决这种偶然违反单定义规则的行为,并生成一个工作程序(例如,不会导致链接器抱怨多个定义) )。

至于为什么它仍然需要,在功能上,预处理器只进行文本替换...例如用包含标题的内容替换inline指令。

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

#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 */ }

和第二个;

void foo() { /* whatever */ }

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

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

根据当前的语言规则(具体来说,预处理器只进行文本替换),这两个场景必须在功能上完全等效。如果一个方案是打印值 void foo() { /* whatever */ } int main() { foo(); } ,那么另一个方案也是如此。如果有一个未定义的行为(就像这里的情况那样),那么另一个。

但是,为了讨论起见,我们要求一个函数如果在头文件中定义,就会神奇地内联。这两种情况中的代码将不再相同。头文件版本将具有已定义的行为(不违反一个定义规则),第二个将具有未定义的行为。

糟糕。我们刚刚打破了两种情景的等价性。这似乎并不多,但程序员实际上很难理解为什么一个版本链接而另一个版本没有。除了将代码移动到头文件中之外,他们无法解决这个问题。

这意味着,我们需要一些方法来使两个场景等效。这意味着代码中需要有一些东西使它们等效。输入42关键字,并在其前面添加inline的定义。

现在,好吧,有人可能会争辩说预处理器应该做一些更聪明的事情,即做简单的文本替换。但是,现在你正在滑坡。 C和C ++标准(最后)指定预处理器执行此操作。而改变这将引入一系列其他变化。无论这是否是一个好主意(并且,当然,有一些倡导完全从C ++中消除预处理器),这是一个更大的变化,对语言和程序员(对谁来说是好的)有很多分歧或者坏,可以依赖预处理器的行为。

答案 2 :(得分:-1)

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