首页 > 其他分享 >关于内联函数(实际使用的例子)

关于内联函数(实际使用的例子)

时间:2024-12-11 21:27:24浏览次数:6  
标签:调用 函数 函数调用 编译器 vector 例子 内联

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. 函数体大小:

  • 普通函数:可以定义任意复杂的函数,不受函数体大小的限制。
  • 内联函数:适用于 短小且简单的函数,如果函数体非常复杂,使用内联可能会增加编译器的负担,导致代码膨胀,甚至可能影响性能。

内联函数的注意事项

  1. 编译器优化:
    • 内联函数并非强制要求,即使你使用了 inline 关键字,编译器也不一定会将其内联展开。编译器会根据函数的复杂度和调用频率来决定是否内联。如果内联函数过于复杂或其体积较大,编译器可能会忽略 inline 指示符,采用普通函数调用方式
  1. 代码膨胀:
    • 由于每次调用内联函数时,都会将函数体直接复制到调用点,如果内联函数被调用得非常频繁,代码的体积可能会大幅增加,甚至影响程序性能(例如,增加缓存未命中的可能性)。
  1. 内联函数的递归问题:
    • 递归函数不能作为内联函数,因为递归会导致编译器无法展开函数体。
  1. 内联函数的定义位置:
    • 内联函数通常需要在头文件中定义,这样每个源文件都能看到函数的定义,以便编译器在每个调用点将其展开。
    • 例如,通常在 .h 文件中定义内联函数,在 .cpp 文件中不再定义该函数。

实际使用例子

我做的一道力扣题,使用了sort函数,对于其写的cmp(比较器),使用内联以及不使用内联,运行效率差别很大。

详见另一篇文章:力扣打卡11:合并区间(比较器内联,引用传参的优化)-CSDN博客

题目链接:56. 合并区间 - 力扣(LeetCode)

我的代码:

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

相关文章

  • c#委托 ,自定义函数中使用委托
    Func<int,int,int>t=(j,i)=>i+j;//自定义委托Func表示有返回值,返回两个的和Console.WriteLine(t(6,4));//输出10Func<int,bool>a=delegate(intj){returnj>0;};Console.WriteLine(a(6));......
  • C++中的虚函数和纯虚函数
     在C++中,虚函数和纯虚函数都有助于实现多态性,但它们之间有几个重要的区别。 一、虚函数(VirtualFunction)1.定义:当你在基类中使用virtual关键字声明一个成员函数时,你就创建了一个虚函数。这意味着即使通过基类指针或引用调用了该函数,实际执行的可能是派生类中重写的......
  • Flask 视图函数
    视图函数是Flask应用中的核心部分,它负责处理请求并生成响应。视图函数与路由紧密结合,通过路由将URL映射到具体的视图函数。以下是对Flask视图函数的详细说明,包括如何定义、使用请求数据、返回响应、以及如何处理错误等。定义视图函数:视图函数是处理请求并返回响应的核......
  • OpenCV的简单函数
    一、二值化(threshold)1.二值化图二值化图:就是将图像中的像素改成只有两种值,其操作的图像必须是灰度图。2.实现方法,函数阈值法(THRESH_BINARY)反阈值法(THRESH_BINARY_INV)截断阈值法(THRESH_TRUNC):低阈值零处理(THRESH_TOZERO)超阈值零处理(THRESH_TOZERO_INV)OTSU阈......
  • Golang学习笔记_02——函数
    Golang测试功能应用Golang学习笔记_01——包函数文章目录函数1.定义2.返回值3.命名返回值4.可变参数源码Go语言中的函数是一种基本的编程结构,用于封装一段代码,以便在需要时多次调用。函数可以接收参数并返回结果,是实现代码复用和模块化编程的重要手段。1......
  • 【语法】高阶函数:map、filter、sorted、reduce
    map【python】Python高阶函数--map函数的详细语法分析与应用实战_pythonmap-CSDN博客filter【python】Python高阶函数--filter函数的高阶用法解析与应用实战_python的filter函数的用法-CSDN博客sorted【python】Python高阶函数--sorted函数的高阶用法解析与应用实战_高阶函......
  • C语言(函数指针与指针函数)
    函数指针定义:函数指针本质上是指针,它是函数的指针(定义了一个指针变量,变量中存储了函数的地址)。函数都有一个入口地址,所谓指向函数的指针,就是指向函数的入口地址。这里函数名就代表入口地址。函数指针存在的意义:让函数多了一种调用方式函数指针作为形参,可以形式调用(回调......
  • RT-DETR改进策略【损失函数篇】| WIoU v3:针对低质量样本的边界框回归损失函数
    一、背景现有问题:大多数现有工作假设训练数据中的样本都是高质量的,专注于增强边界框回归损失的拟合能力。然而,在低质量样本上盲目增强边界框回归会损害定位性能。解决思路:本文使用Wise-IoU,其动态非单调FM使用异常值程度而非IoU来评估锚框的质量,并提供一种有效的梯度增益......
  • 大模型--ReLU激活函数--31
    目录1参考2.基础np.dotnp.outer1参考“死亡”ReLUs邱锡鹏老师的《神经网络与深度学习》2.基础Sigmoid型函数的两端饱和,ReLU函数为左饱和函数,且在x>0时导数为1,在一定程度上缓解了神经网络的梯度消失问题,加速梯度下降的收敛速度。ReLU也是非线性函数,它将低于或等于......
  • C++_构造函数和析构函数与对象的封装
    头文件和源文件分离源文件--类内声明和类外实现声明和实现分离struct结构的默认访问类型是public,而类为private。POD,PlainOldData只表示纯粹的数据对象classpublicprivate类作用域classscope成员变量成员函数--函数-函数头和函数体-作用域解析运算符(::......