NPS*_*NPS 9 c++ compiler-construction inline
因为它完全取决于编译器是否可以内联我的函数,所以我可以完全停止使用这个关键字(假设它会内联所有内容)?
And*_*owl 12
您可以停止使用inline作为优化技术.
inline仅当您希望不应用ODR(一个定义规则)时,它才基本有用.简而言之,您可以将函数标记为inline并在一个头文件中直接提供它们的定义,然后由多个转换单元导入,而链接器不会抱怨:
foo.hpp
inline int foo() { return 42; }
Run Code Online (Sandbox Code Playgroud)
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();
}
Run Code Online (Sandbox Code Playgroud)
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();
}
Run Code Online (Sandbox Code Playgroud)
inline关键字的存在(同样,不保证编译器将执行内联)确保链接器将合并这些定义.
当然,为了使该合并操作有意义,标记为最终成为若干不同转换单元的一部分的函数的所有定义inline必须相同.如果不是这种情况,您的程序具有未定义的行为,并且不需要诊断 - 这意味着您的编译器/链接器不需要检测此不一致并告诉您出错!
根据C++ 11标准的第3.2/4段,事实上:
每个程序应该只包含该程序中使用的每个非内联函数或变量的一个定义; 无需诊断.该定义可以在程序中明确显示,可以在标准或用户定义的库中找到,或者(在适当的时候)隐式定义(见12.1,12.4和12.8).内联函数应在每个使用它的翻译单元中定义.
请注意,您可以在不同的翻译单元中将相同的功能标记为inline和字面定义两次,只要这些定义相同,就可以了:
Foo.cpp中
inline int foo() // Has the same body in main.cpp, no problem!
{
return 42;
}
Run Code Online (Sandbox Code Playgroud)
main.cpp中
inline int foo() // Has the same body in foo.cpp, no problem!
{
return 42;
}
int main()
{
std::cout << foo();
}
Run Code Online (Sandbox Code Playgroud)
但是,如果两个定义不同,则会在代码中注入UB,如下例所示:
Foo.cpp中
inline int foo()
{
return 42; // <== WATCH OUT! Different body in main.cpp
}
Run Code Online (Sandbox Code Playgroud)
main.cpp中
inline int foo()
{
return -42; // <== WATCH OUT! Different body in foo.cpp
}
int main()
{
std::cout << foo();
}
Run Code Online (Sandbox Code Playgroud)
这就是为什么您通常将函数标记为inline直接在常见的#include头文件中提供其定义的原因.
另请注意,在类定义中直接内联其定义的类成员函数会自动标记为inline.
取决于使用目的inline.
常见(错误)概念:
inline只是编译器可能会或可能不会遵守的建议.一个好的编译器无论如何都会做需要做的事情.
虽然,事实是:
inline通常在实现中指示在调用点处函数体的内联替换优先于通常的函数调用机制.在呼叫点执行此内联替换不需要实现; 但是,即使inline省略了这种替换,也遵循其他规则(尤其是一个定义规则)inline.
因此,如果您的使用目的是优化,答案是:
是的,你可以停止使用
inline.大多数现代编译器都会为你做得很好.
但是,如果您的使用目的inline是允许您通过一个定义规则并在头文件中定义一个函数体而不破坏ODR,那么答案是:
不,您需要明确标记功能
inline以便能够绕过ODR.
注意:类主体中定义的成员函数是隐式的inline,但同样不适用于自由函数.