我可以完全停止使用“内联”吗?

时间:2013-04-07 12:58:04

标签: c++ compiler-construction inline

由于完全取决于编译器是否内联我的函数,我可以完全停止使用这个关键字(假设它会内联所有内容)?

2 个答案:

答案 0 :(得分:12)

您可以停止使用inline作为优化技术

仅当您希望ODR (One Definition Rule)不适用时,

inline才基本有用。简而言之,您可以将函数标记为inline并直接在一个头文件中提供它们的定义,然后由多个翻译单元导入,而链接器不会抱怨这一点:

<强> foo.hpp

inline int foo() { return 42; }

<强> Foo.cpp中

#include "foo.hpp" // <== THE LINKER WOULD COMPLAIN IF foo() WERE NOT inline,
                   //     because its definition is imported also in main.cpp
void bar()
{
    int x = foo();
}

<强>的main.cpp

#include "foo.hpp" // <== THE LINKER WOULD COMPLAIN IF foo() WERE NOT inline,
                   //     because its definition is imported also in foo.cpp
int main()
{
    std::cout << foo();
}

inline关键字的存在(同样,不保证编译器将执行内联)确保链接器将合并这些定义。

当然,为了使这个合并操作有意义, all 标记为inline的函数的定义最终成为几个不同翻译单元的一部分必须相同。如果不是这种情况,您的程序有未定义的行为,并且不需要诊断 - 这意味着您的编译器/链接器不需要检测到这种不一致并告诉您出现问题!

根据C ++ 11标准的第3.2 / 4段,事实上:

  

每个程序都应包含每个非内联函数或odr使用的变量的一个定义   在该计划中;无需诊断。定义可以在程序中明确显示,可以找到   在标准或用户定义的库中,或(在适当的时候)它是隐式定义的(见12.1,12.4和   12.8)。内联函数应在每个使用它的翻译单元中定义。

请注意,您可以在不同的翻译单元中使用相同的功能标记为inline并在字面上定义两次,只要这些定义相同,就可以了:

<强> Foo.cpp中

inline int foo() // Has the same body in main.cpp, no problem!
{
    return 42;
}

<强>的main.cpp

inline int foo() // Has the same body in foo.cpp, no problem!
{
    return 42;
}

int main()
{
    std::cout << foo();
}

但是,如果两个定义不同,您将在代码中注入UB,如下例所示:

<强> Foo.cpp中

inline int foo()
{
    return 42;  // <== WATCH OUT! Different body in main.cpp
}

<强>的main.cpp

inline int foo()
{
    return -42; // <== WATCH OUT! Different body in foo.cpp
}

int main()
{
    std::cout << foo();
}

这就是为什么当您直接在常见inline d头文件中提供其定义时,通常将函数标记为#include

另请注意,在类定义中直接内联其定义的类成员函数会自动标记为inline

答案 1 :(得分:5)

取决于使用inline

常见(错误)概念:
inline只是编译器可能会或可能不会遵守的建议。一个好的编译器无论如何都会做需要做的事情。

然而,真相:

inline通常向实现指示在调用点处函数体的内联替换优先于通常的函数调用机制。在呼叫点执行此内联替换不需要实现;但是,即使省略此inline替换,也会遵循inline的其他规则(尤其是 One Definition Rule )。 < / p>

因此,如果您的使用目的是优化,答案是:

  

是,您可以停止使用inline。大多数现代编译器都会为你做得很好

但是,如果您使用inline的目的是允许您通过一个定义规则并在头文件中定义一个函数体而不破坏ODR,那么答案是:

  

不,您需要明确将功能标记为inline才能绕过ODR。

注意:类主体中定义的成员函数是隐式inline,但同样不适用于自由函数。