C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++ 内联函数

C++ 内联函数inline Function示例详解

作者:点云SLAM

文章介绍了C++内联函数的含义、内联展开、编译器何时内联以及内联对链接和性能的影响,内联函数允许在头文件中定义函数,以避免ODR错误,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧

1. 内联函数的本质

C++ 中的 inline 有两个含义:

(1) 允许函数在多个翻译单元中重复定义

用于放宽 ODR(One Definition Rule)。
→ 这是 inline 最重要的实际用途。

(2) 作为性能优化提示

告诉编译器“可以内联展开”。
→ 编译器可以忽略,不是强制。

2. 内联展开是什么?

通常函数调用包含跳转、压栈、返回等开销。
内联展开 = 把函数代码直接拷贝到调用点,避免调用开销。

示例:

inline int sqr(int x) { return x * x; }

展开后等价于直接写 x * x

3. 编译器何时会内联?

编译器的优化器根据启发式决定:

会内联的典型情况:

不会内联的情况:

4. inline 对链接的影响

普通函数只能在一个 .cpp 中定义,否则多重定义错误。

但 inline 函数可以这样:

// foo.h
inline int add(int a, int b) { return a + b; }

然后出现在多个 cpp 中,链接器会合并。

类内定义的函数默认 inline,因此类成员函数出现在头文件是合法的。

模板函数也是同理(模板必须写在头文件)。

5. inline vs 宏

对比项inline
类型检查
作用域文本替换
调试支持
常见用途小函数简单表达式、条件编译

一般规则:能用 inline,就不要用宏。

6. inline 对性能的真实影响

正面:

负面:

因此:

内联最有效的场景:频繁调用的小函数(数学计算、向量操作)。

(Eigen、Sophus、GTSAM 都这么做)

7. 工程中内联的推荐模式

应当内联:

不要内联:

8. 常见误区

误区 1:加 inline 就会内联

事实:编译器完全可以忽略。

误区 2:内联一定加速

事实:大函数内联反而变慢。

误区 3:inline 主要用来优化性能

事实:inline 的核心用途是允许头文件重复定义函数。

9. 精简总结

10.C++ 内联函数综合示例

1.最常用:类内定义 = 默认内联

class Vec3 {
public:
    double x, y, z;
    // 类内定义 → 默认 inline
    double norm2() const { 
        return x * x + y * y + z * z; 
    }
    void scale(double s) {
        x *= s; y *= s; z *= s;
    }
};

特点:

2.类外定义 but 内联:适用于头文件工具函数

// vec_utils.h
#pragma once
inline double dot(const Vec3& a, const Vec3& b) {
    return a.x*b.x + a.y*b.y + a.z*b.z;
}

为什么要 inline?

因为头文件中定义函数,如果不 inline → 多重定义。

适合:数学工具函数、小型转换函数、小 lambda 替代。

3.模板函数天然 inline

SLAM & 点云处理中大量用的模板代码本质都是 inline:

template<typename T>
inline T clamp(T v, T lo, T hi) {
    return (v < lo) ? lo : (v > hi) ? hi : v;
}

其实模板函数不写 inline 也能 inline,因为:

4.内联 + constexpr(超轻量函数最佳组合)

constexpr inline double deg2rad(double deg) {
    return deg * 3.14159265358979323846 / 180.0;
}

用途:

5.内联 setter / getter

强烈推荐用于性能敏感代码(尤其是数学类型/几何类):

class Pose {
public:
    inline double x() const { return tx; }
    inline void setX(double v) { tx = v; }
private:
    double tx;
};

现代 C++ get/set 可 inline 解决跳转开销。

6.内联 + forceinline 强制内联(GCC/Clang/MSVC)

对于高度性能敏感的代码(例如点云 ICP 内循环):

#if defined(_MSC_VER)
#define FORCE_INLINE __forceinline
#else
#define FORCE_INLINE __attribute__((always_inline)) inline
#endif
FORCE_INLINE double sqr(double x) { return x * x; }

注意:

7.与 static inline 结合用于 header-only 工具库

可避免 ODR 冲突:

// math_utils.h
#pragma once
static inline double fast_min(double a, double b) {
    return (a < b) ? a : b;
}

推荐场景:
头文件单独工具函数,但不希望暴露全局符号。

8.类模板内联成员函数(Eigen, Sophus, SLAM 常用写法)

template<typename T>
class Box {
private:
    T min_, max_;
public:
    inline T size() const { return max_ - min_; }
    inline bool contains(const T& x) const { return x >= min_ && x <= max_; }
};

典型用途:Bounding box、SE(3)、SO(3) 数学类型等。

9.内联函数的真实性能对比(示例)

非内联版本(有函数调用开销)

double sqr(double x) { return x*x; }
double sum(const std::vector<double>& v) {
    double s = 0;
    for(double x : v) s += sqr(x);
    return s;
}

编译器可能无法展开(尤其跨文件编译时)。

内联版本(更易优化)

inline double sqr(double x) { return x*x; }

优势:

10.完整示例:内联 + 模板 + 内联类成员

这是一个仿 SLAM 库的小型数学类型示例:

#pragma once
#include <cmath>
class Vec3 {
public:
    double x, y, z;
    inline Vec3(double X, double Y, double Z)
        : x(X), y(Y), z(Z) {}
    inline double dot(const Vec3& o) const {
        return x*o.x + y*o.y + z*o.z;
    }
    inline Vec3 operator+(const Vec3& o) const {
        return Vec3(x+o.x, y+o.y, z+o.z);
    }
    inline Vec3 normalized() const {
        double n = std::sqrt(dot(*this));
        return Vec3(x/n, y/n, z/n);
    }
};
// 工具函数(header-only)
inline double distance(const Vec3& a, const Vec3& b) {
    return (a + Vec3(-b.x, -b.y, -b.z)).normalized().dot(a);
}

这是 SLAM / ICP / 点云算法中常见的数学类写法:
全都 inline,以消除函数开销,加速内循环。

小结:内联函数的最佳工程实践

场景是否 inline
类内部定义自动 inline,推荐
头文件小工具函数必须 inline
模板函数自动 inline, OK
性能敏感数学函数inline 或 forceinline
大型函数不推荐(代码膨胀)
接口函数(虚函数)不能 inline

到此这篇关于C++ 内联函数(inline Function)详解的文章就介绍到这了,更多相关C++ 内联函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文