← Назад к вопросам

Что такое inline функция? Когда её стоит использовать?

1.2 Junior🔥 101 комментариев
#Сборка и инструменты#Структуры данных и алгоритмы#Язык C++

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Inline функции в C++

Inline функция — это подсказка компилятору заменить вызов функции на её тело (inline substitution). Вместо jump на функцию и возврата, компилятор копирует код функции прямо в место вызова. Это может улучшить производительность за счёт избежания overhead'а вызова функции.

Синтаксис

// Явное указание inline
inline int square(int x) {
    return x * x;
}

// Или в классе (implicit inline)
class MyClass {
public:
    int getValue() { return value; }  // Автоматически inline
    
    int getValue2();  // Не inline
};

int MyClass::getValue2() { return value; }

Что происходит при inline

Без inline:

int square(int x) { return x * x; }

int main() {
    int result = square(5);  // Вызов функции
}

// Машинный код:
// 1. Сохрани адрес возврата в stack
// 2. Перейди на square()
// 3. Вычисли x * x
// 4. Верни результат
// 5. Продолжи выполнение

С inline:

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

int main() {
    int result = square(5);  // Компилятор заменит на: int result = 5 * 5;
}

// Машинный код:
// int result = 5 * 5;  // Прямой код, без вызова функции

Преимущества

1. Улучшение производительности

// Без inline
inline int add(int a, int b) {
    return a + b;
}

// Вместо:
// call add
// ret

// Получаем:
// add eax, edx  // Прямая команда процессора

2. Избежание overhead'а вызова функции

  • Сохранение регистров
  • Передача параметров
  • Адрес возврата
  • Переключение контекста CPU

3. Возможность оптимизации компилятором

inline int multiply(int a, int b) {
    return a * b;
}

// Если вызвать с константами
int result = multiply(5, 3);
// Компилятор сразу вычислит = 15 (constant folding)

Когда использовать inline

Очень маленькие функции (1-3 строки):

// ХОРОШО
inline bool is_positive(int x) {
    return x > 0;
}

// Вызовется миллион раз в цикле
for (int i = 0; i < 1000000; i++) {
    if (is_positive(data[i])) { /* ... */ }
}
// Без inline это медленнее

Функции в hot path (часто вызываемые):

// Критичная функция, вызывается часто
inline float distance(float x1, float y1, float x2, float y2) {
    float dx = x2 - x1;
    float dy = y2 - y1;
    return std::sqrt(dx * dx + dy * dy);
}

Геттеры и сеттеры:

class Point {
    float x, y;
    
public:
    // Идеально для inline
    inline float getX() const { return x; }
    inline float getY() const { return y; }
    
    inline void setX(float val) { x = val; }
};

Когда НЕ использовать inline

Большие функции (много кода):

// ПЛОХО — код раздувается
inline void process_data(const std::vector<int>& data) {
    for (const auto& item : data) {
        // 50 строк кода...
    }
}

// Если вызвать 10 раз, код увеличится в 10 раз → cache misses → МЕДЛЕННЕЕ!

Рекурсивные функции:

// Бессмысленно
inline int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);  // Рекурсия не инлайнится
}

Виртуальные функции:

class Base {
public:
    virtual inline void func() {  // inline не помогает с виртуальным вызовом
        // Во время runtime всё равно будет virtual dispatch
    }
};

Функции с побочными эффектами:

// ПЛОХО
inline void print_and_add(int& x) {
    std::cout << x;  // I/O операция
    x++;
}

// Inline может нарушить порядок выполнения побочных эффектов

Пример: влияние inline на производительность

// Тест 1: без inline
int add_no_inline(int a, int b) {
    return a + b;
}

// Тест 2: с inline
inline int add_inline(int a, int b) {
    return a + b;
}

int main() {
    // 1 миллиард вызовов
    int sum = 0;
    for (int i = 0; i < 1000000000; i++) {
        // sum += add_no_inline(i, i+1);  // Может быть на 30-50% медленнее
        sum += add_inline(i, i+1);       // Быстро: просто add edx, edx
    }
}

Встроенные функции vs явный inline

// Все эти функции автоматически инлайнятся:

// 1. Функции в теле класса
class MyClass {
public:
    void small_func() { x++; }  // Автоматически inline
};

// 2. Функции в header файле
inline void utility() { }

// 3. Шаблонные функции
template<typename T>
void process(T x) { }

// Компилятор часто игнорирует явный inline (это лишь подсказка)
// Современные компилеры сами решают, инлайнить или нет

Проблемы с inline

1. Code bloat (раздувание кода)

inline void big_function() {
    // 100 строк...
}

// Если вызвать 50 раз, получим 50 копий кода → размер бинарника ↑ → cache misses ↑

2. Сложнее отлаживать

// Без inline: простой breakpoint в функции
// С inline: может быть оптимизирована так, что отладка невозможна

3. Нарушение инкапсуляции

// Если inline функция в header, её реализация видна
// Нельзя менять реализацию без пересборки всего проекта

Рекомендации

// Используй inline для:
inline int getSize() const { return size; }
inline bool isEmpty() const { return size == 0; }
inline float clamp(float x) { return std::max(0.f, std::min(1.f, x)); }

// НЕ используй inline для:
// - Функции > 10-20 строк
// - Функции с циклами
// - Функции с условными переходами
// - Виртуальные функции

// Доверься компилятору:
// Современные компилеры (gcc, clang, msvc) умны:
// - Они инлайнят автоматически, если видят пользу
// - Указание inline часто игнорируется в пользу -O2/-O3

Измерение эффекта

// -O0 (без оптимизации)
// inline может дать 10-30% улучшение

// -O2 или -O3 (с оптимизацией)
// inline часто уже применён автоматически
// Явный inline может не дать никакого выигрыша

// В modern C++ (C++17+)
// Используй [[gnu::always_inline]] если критично
int get_value() [[gnu::always_inline]] { return value; }

Inline — это микрооптимизация, которая имеет смысл для очень маленьких функций в hot path. Современные компилеры обычно сами решают, что инлайнить, поэтому надо доверять optimizer'у.