目录:
0. 内联函数作用
在C语言中,我们使用 带参数的宏定义 这种借助编译器的优化技术来减少程序的执行时间,那么在C++中有没有相同的技术或者更好的实现方法呢?
答案是有的,那就是 内联(inline)函数。内联函数作为 编译器优化手段 的一种技术,在降低运行时间上非常有用。
1. 什么是内联函数
内联函数 是C++的增强特性之一,用来降低程序的运行时间。当内联函数收到编译器的指示时,即可发生内联:编译器将使用函数的定义体来替代函数调用语句,这种替代行为发生在编译阶段而非程序运行阶段。
定义函数时,在函数的前面以关键字“inline”声明函数,即可使函数称为内联声明函数。
inline
int max(int x, y)
{
return x > y ? x : y;
}
2. 内联函数和带参数的宏定义
带参数的宏定义是在预处理阶段展开,inline内联函数实在编译阶段展开
从是《Effective C++》中的 “Prefer consts,enums,and inlines to #defines” ,到《高质量程序设计指南——C++/C语言》中的 “用函数内联取代宏”。
到书 《高质量程序设计指南——C++/c语言》的解释:
1. 使用宏代码最大的缺点是容易出错,预处理器在宏代码时常常产生意想不到的边际效应;
2. 宏的另一个缺点就是无法调试,但是内联函数可以调试;
3. 对于C++,使用宏代码还有另一种缺点:无法操作类的私有成员数据
4. 内联函数的另一优点:函数被内联后,编译器就可以通过上下文相关的优化技术对结果代码执行更深入的优化
例1:宏定义和内联函数
#include <iostream>
using std::cout;
using std::endl;
#define MULT(a, b) (a * b)
#define MULT2(a, b) ((a) * (b))
inline
int mult(int val1, int val2)
{
return val1*val2;
}
int main()
{
int val1 = 3, val2 = 7;
cout << "MUlT is " << MULT(1 + 2, 3 + 4) << endl; // 1 + 2 * 3 + 4
cout << "MUlT2 is " << MULT2(1 + 2, 3 + 4) << endl; // (1 + 2)*(3 + 4)
cout << "mult is " << mult(val1, val2) << endl; //内联函数
return 0;
}
3. 将内联函数放入头文件
关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用。如下 func 函数不能成为内联函数:
//error:头文件中声明inline
inline void func(int x, int y);
//实现在.cpp文件中
void func(int x, int y)
{ //实现... }
应在头文件直接定义
inline
void func(int x, in y)//该语句在头文件中
{ //实现... }
所以说,C++ inline函数是一种“用于实现的关键字”,而不是一种“用于声明的关键字”。一般地,用户可以阅读函数的声明,但是看不到函数的定义。这个细节虽然不会影响函数的功能,但是体现了高质量C++/C 程序设计风格的一个基本原则:声明与定义不可混为一谈,用户没有必要、也不应该知道函数是否需要内联。
内联函数应该在头文件中定义,这一点不同于其他函数。编译器在调用点内联展开函数的代码时,必须能够找到 inline函数的定义才能将调用函数替换为函数代码,而对于在头文件中仅有函数声明是不够的。
当然内联函数定义也可以放在源文件中,但此时只有定义的那个源文件可以用它, 而且必须为每个源文件拷贝一份定义(即每个源文件里的定义必须是完全相同的),当然即使是放在头文件中,也是对每个定义做一份拷贝,只不过是编译器替你完成这种拷贝罢了。但相比于放在源文件中,放在头文件中既能够确保调用函数是定义是相同的,又能够保证在调用点能够找到函数定义从而完成内联(替换)。
(不要有for/while等复杂的代码,否则inline很容易造成代码膨胀)
4. 谨慎地使用内联
内联能提高函数的执行效率,为什么不把所有的函数都定义成内联函数?
以下摘自《高质量程序设计指南 — C/C++语言》:
所以使用内联时,应该按情况谨慎使用