C++ 内联函数(inline function)是指在编译时将函数调用直接替换为函数体的代码,从而避免函数调用的开销。
1.它通常用于短小的函数,以提高程序的执行效率。
2.内联函数通过在函数声明前加上 inline 关键字来定义。
3.使用内联函数可以减少函数调用的栈操作,但过度使用可能增加代码体积,导致性能下降。
#include <iostream>
using namespace std;
// 内联函数
inline int add(int a, int b) {
return a + b;
}
int main() {
int x = 5, y = 3;
cout << "Sum: " << add(x, y) << endl; // 内联函数调用
return 0;
}
内联函数与普通函数的区别
内联函数(inline function)和普通函数(regular function)在 C++ 中的主要区别在于函数调用的处理方式和性能优化。我们逐一来看:
1. 函数调用机制:
- 普通函数:普通函数在调用时,会执行以下步骤:
- 跳转到函数的地址(栈帧创建)。
- 执行函数的代码。
- 返回到调用点(栈帧销毁)。
因此,普通函数的调用会有一定的开销,尤其是在频繁调用时,栈操作和跳转可能影响性能。
- 内联函数:内联函数在编译时,编译器会 将函数体直接插入到调用点,从而 避免了函数调用的开销。也就是说,内联函数并不执行常规的跳转操作,而是直接用函数体替代函数调用。这通常会提高性能,特别是在函数体小且频繁调用的情况下。
2. 性能:
- 普通函数:普通函数的性能受到函数调用机制的影响,存在栈操作、跳转等开销,特别是对于小函数,可能会显得低效。
- 内联函数:内联函数可以提高性能,避免了函数调用的开销,尤其是当函数体较小、调用频繁时。
3. 代码大小:
- 普通函数:普通函数的代码量不会因为函数调用的次数增加而膨胀,函数体在程序中只有一份。
- 内联函数:内联函数的代码体会在每个调用点插入,可能会导致代码体积膨胀,特别是在函数调用频繁且函数体较大的情况下。
4. 函数体大小:
- 普通函数:可以定义任意复杂的函数,不受函数体大小的限制。
- 内联函数:适用于 短小且简单的函数,如果函数体非常复杂,使用内联可能会增加编译器的负担,导致代码膨胀,甚至可能影响性能。
内联函数的注意事项
- 编译器优化:
-
- 内联函数并非强制要求,即使你使用了 inline 关键字,编译器也不一定会将其内联展开。编译器会根据函数的复杂度和调用频率来决定是否内联。如果内联函数过于复杂或其体积较大,编译器可能会忽略 inline 指示符,采用普通函数调用方式
- 代码膨胀:
-
- 由于每次调用内联函数时,都会将函数体直接复制到调用点,如果内联函数被调用得非常频繁,代码的体积可能会大幅增加,甚至影响程序性能(例如,增加缓存未命中的可能性)。
- 内联函数的递归问题:
-
- 递归函数不能作为内联函数,因为递归会导致编译器无法展开函数体。
- 内联函数的定义位置:
-
- 内联函数通常需要在头文件中定义,这样每个源文件都能看到函数的定义,以便编译器在每个调用点将其展开。
- 例如,通常在 .h 文件中定义内联函数,在 .cpp 文件中不再定义该函数。
实际使用例子
我做的一道力扣题,使用了sort函数,对于其写的cmp(比较器),使用内联以及不使用内联,运行效率差别很大。
详见另一篇文章:力扣打卡11:合并区间(比较器内联,引用传参的优化)-CSDN博客
我的代码:
class Solution {
public:
static bool cmp(vector<int> A,vector<int> B)
{
return A[0]<B[0];
}
vector<vector<int>> merge(vector<vector<int>>& intervals) {
//调用自己写的比较器,尤其是静态的,不会内联。每次调用比较函数都会有额外的函数调用开销。
//sort(intervals.begin(),intervals.end(),cmp);
//默认的比较器默认比较intervals[i][0]
//sort(intervals.begin(),intervals.end());
//lambda表达式,会内联
sort(intervals.begin(), intervals.end(), [](const vector<int>& A, const vector<int>& B) {
return A[0] < B[0];
});
vector<vector<int>> ans;
vector<int> t=intervals[0];
for(int i=1;i<intervals.size();i++)
{
if(t[1]<intervals[i][0])
{
ans.push_back(t);
t=intervals[i];
}
else
{
t[1]=max(t[1],intervals[i][1]);
}
}
ans.push_back(t);
return ans;
}
};
我首先用了自己写的静态比较器(因为sort不是类内函数,cmp如果不是静态,就会报错)(将cmp写在类外也行),但是这样的话,排序的每次比较,都会调用函数,造成开销,同时是值传递,会复制值,造成开销。因此程序运行时的速度会很慢。
但是,我们可以使用内联,增加编译的时间,减少运行的时间。可以通过以下方法内联:
1.lambda表达式
2.sort默认比较器(默认的比较器会内联,并且是引用传递)
3.inline标记函数,注意要const。因为sort传递给比较函数的参数通常是const对象,因此函数签名与默认行为不匹配,可能导致编译器拒绝内联,甚至报错。
inline bool cmp(const vector<int>& A, const vector<int>& B) {
return A[0] < B[0];
}
当然,还可以使用引用传递,避免复制值,直接传递地址,防止造成的额外开销,(其实值的复制
才是最影响效率的)
bool cmp(vector<int>& A,vector<int>& B)
{
return A[0]<B[0];
}
通过比较,可以看到,这方面的优化会提升不少i的程序运行效率。
标签:调用,函数,函数调用,编译器,vector,例子,内联 From: https://blog.csdn.net/Bigkinder/article/details/144358413