在c++中使用内联函数的优点/缺点是什么?我看到它只提高了编译器输出的代码的性能,但随着今天优化的编译器,快速的cpu,巨大的内存等(不像在1980年<内存是稀缺的,所有东西都必须适合100KB内存),他们今天真正有什么优势?
当前回答
在古老的C和c++中,内联就像寄存器:给编译器一个关于可能的优化的建议(只不过是一个建议)。
在现代c++中,内联告诉链接器,如果在不同的翻译单元中发现了多个定义(不是声明),那么它们都是相同的,链接器可以自由地保留其中一个,并丢弃所有其他的定义。
如果一个函数(无论多么复杂或“线性”)定义在头文件中,内联是强制的,以允许多个源包含它而不会被链接器产生“多个定义”错误。
默认情况下,类内部定义的成员函数是“内联”的,模板函数也是如此(与全局函数相反)。
//fileA.h
inline void afunc()
{ std::cout << "this is afunc" << std::endl; }
//file1.cpp
#include "fileA.h"
void acall()
{ afunc(); }
//main.cpp
#include "fileA.h"
void acall();
int main()
{
afunc();
acall();
}
//output
this is afunc
this is afunc
注意fileA.h包含在两个.cpp文件中,导致两个afunc()实例。 链接器将丢弃其中一个。 如果没有指定inline,链接器将报错。
其他回答
我想补充一点,在构建共享库时,内联函数是至关重要的。如果不将函数标记为内联,则它将以二进制形式导出到库中。如果导出,它也将出现在符号表中。另一方面,内联函数不会被导出,既不会被导出到库二进制文件中,也不会被导出到符号表中。
当库打算在运行时加载时,它可能是关键的。它还可能打击二进制兼容的库。在这种情况下,不要使用内联。
Why not make all functions inline by default? Because it's an engineering trade off. There are at least two types of "optimization": speeding up the program and reducing the size (memory footprint) of the program. Inlining generally speeds things up. It gets rid of the function call overhead, avoiding pushing then pulling parameters from the stack. However, it also makes the memory footprint of the program bigger, because every function call must now be replaced with the full code of the function. To make things even more complicated, remember that the CPU stores frequently used chunks of memory in a cache on the CPU for ultra-rapid access. If you make the program's memory image big enough, your program won't be able to use the cache efficiently, and in the worst case inlining could actually slow your program down. To some extent the compiler can calculate what the trade offs are, and may be able to make better decisions than you can, just looking at the source code.
优势
通过在需要的地方内联代码,程序将在函数调用和返回部分花费更少的时间。它应该使您的代码运行得更快,即使它变得更大(见下文)。内联普通访问器可以是有效内联的一个例子。 通过将其标记为内联,你可以将函数定义放在头文件中(即它可以包含在多个编译单元中,而链接器不会抱怨)
缺点
It can make your code larger (i.e. if you use inline for non-trivial functions). As such, it could provoke paging and defeat optimizations from the compiler. It slightly breaks your encapsulation because it exposes the internal of your object processing (but then, every "private" member would, too). This means you must not use inlining in a PImpl pattern. It slightly breaks your encapsulation 2: C++ inlining is resolved at compile time. Which means that should you change the code of the inlined function, you would need to recompile all the code using it to be sure it will be updated (for the same reason, I avoid default values for function parameters) When used in a header, it makes your header file larger, and thus, will dilute interesting informations (like the list of a class methods) with code the user don't care about (this is the reason that I declare inlined functions inside a class, but will define it in an header after the class body, and never inside the class body).
内联魔法
The compiler may or may not inline the functions you marked as inline; it may also decide to inline functions not marked as inline at compilation or linking time. Inline works like a copy/paste controlled by the compiler, which is quite different from a pre-processor macro: The macro will be forcibly inlined, will pollute all the namespaces and code, won't be easily debuggable, and will be done even if the compiler would have ruled it as inefficient. Every method of a class defined inside the body of the class itself is considered as "inlined" (even if the compiler can still decide to not inline it Virtual methods are not supposed to be inlinable. Still, sometimes, when the compiler can know for sure the type of the object (i.e. the object was declared and constructed inside the same function body), even a virtual function will be inlined because the compiler knows exactly the type of the object. Template methods/functions are not always inlined (their presence in an header will not make them automatically inline). The next step after "inline" is template metaprograming . I.e. By "inlining" your code at compile time, sometimes, the compiler can deduce the final result of a function... So a complex algorithm can sometimes be reduced to a kind of return 42 ; statement. This is for me extreme inlining. It happens rarely in real life, it makes compilation time longer, will not bloat your code, and will make your code faster. But like the grail, don't try to apply it everywhere because most processing cannot be resolved this way... Still, this is cool anyway...:-p
这并不完全是关于性能。c++和C都用于嵌入式编程,位于硬件之上。例如,如果您要编写中断处理程序,则需要确保代码可以立即执行,而不会交换额外的寄存器和/或内存页。这就是内联派上用场的时候。好的编译器在需要速度时自己做一些“内联”,但“内联”迫使它们这样做。
Generally speaking, these days with any modern compiler worrying about inlining anything is pretty much a waste of time. The compiler should actually optimize all of these considerations for you through its own analysis of the code and your specification of the optimization flags passed to the compiler. If you care about speed, tell the compiler to optimize for speed. If you care about space, tell the compiler to optimize for space. As another answer alluded to, a decent compiler will even inline automatically if it really makes sense.
另外,正如其他人所说,使用内联并不能保证任何东西都是内联的。如果你想要保证它,你必须定义一个宏而不是一个内联函数来实现它。
何时内联和/或定义宏强制包含?-只有当你对关键代码段的速度有了证明和必要的提高,并且知道这对应用程序的整体性能有影响时。
推荐文章
- 为什么我的程序不能在Windows 7下用法语编译?
- 如何获取变量的类型?
- 什么是奇怪的重复模板模式(CRTP)?
- 连接两个向量的最佳方法是什么?
- 在c++中,是通过值传递更好,还是通过引用到const传递更好?
- 在STL中deque到底是什么?
- Windows上最好的免费c++分析器是什么?
- 如何自动转换强类型枚举为int?
- 在一个类中使用具有成员函数的泛型std::function对象
- 'for'循环中的后增量和前增量产生相同的输出
- 虚函数和纯虚函数的区别
- c++中的_tmain()和main()有什么区别?
- 内存泄漏是否正常?
- 当启用c++ 11时,std::vector性能回归
- 什么时候使用哪种指针?