Что не так с использованием встроенных функций?

Хотя в некоторых ситуациях было бы очень удобно использовать встроенные функции,

Есть ли недостатки с встроенными функциями?

Заключение

По-видимому, нет ничего плохого в использовании встроенных функций.

Но стоит отметить следующие моменты!

  • Чрезмерное использование встраивания может фактически замедлить работу программ. В зависимости от размера функции вложение может привести к увеличению или уменьшению размера кода. Вложение очень маленькой функции доступа обычно уменьшает размер кода, в то время как вложение очень большой функции может значительно увеличить размер кода. На современных процессорах меньший код обычно работает быстрее из-за лучшего использования кэша команд. - Руководство Google

  • Преимущества скорости встроенных функций, как правило, уменьшаются по мере увеличения размера функции. В какой-то момент накладные расходы на вызов функции становятся малыми по сравнению с исполнением тела функции, а преимущество теряется - Источник

  • Существует несколько ситуаций, когда встроенная функция может не работать:

    • Для функции, возвращающей значения; если существует оператор return.
    • Для функции, не возвращающей никаких значений; если существует оператор loop, switch или goto.
    • Если функция рекурсивна. - Источник
  • Ключевое слово __inline заставляет функцию быть встроенной, только если вы указываете опцию оптимизации. Если задана оптимизация, выполняется ли выполнение __inline, зависит от настройки параметра встроенного оптимизатора. По умолчанию встроенная опция действует всякий раз, когда запускается оптимизатор. Если вы укажете оптимизацию, вы также должны указать параметр noinline, если хотите, чтобы ключевое слово __inline игнорировалось. - Источник

Ответ 1

Стоит отметить, что ключевое слово inline на самом деле просто подсказка для компилятора. Компилятор может игнорировать встроенный и просто генерировать код для функции где-то.

Основным недостатком встроенных функций является то, что он может увеличить размер исполняемого файла (в зависимости от количества экземпляров). Это может быть проблемой на некоторых платформах (например, встраиваемых системах), особенно если сама функция является рекурсивной.

Я также рекомендовал бы делать inline'd функции очень маленькие. Преимущества скорости встроенных функций, как правило, уменьшаются по мере роста размера функции. В какой-то момент накладные расходы на вызов функции становятся малыми по сравнению с исполнением тела функции, и преимущество теряется.

Ответ 2

Он может увеличить размер  исполняемый файл, и я не думаю  компиляторы всегда будут  они встроены, хотя вы использовали  ключевое слово inline. (Или это другое  путь, как будто Вайбхав  сказал?...)

Я думаю, что это нормально, если  функция имеет только 1 или 2 оператора.

Изменить: Вот что говорит об этом документ linux CodingStyle:

Глава 15: Врожденное заболевание

Похоже, неправильное восприятие, что gcc имеет волшебство "ускорить" ускорение "в очереди". Хотя использование встроенных быть подходящим (например, как средство замены макросов, см. главу 12), его очень часто нет. Обилие использования ключевое слово inline приводит к большего ядра, что, в свою очередь, замедляет системы в целом, из-за больший размер icache для процессора и просто потому, что есть меньше память доступна для pagecache. Просто подумай об этом; промах пагека вызывает поиск диска, что легко 5 милисекунд. Есть много CPU циклы, которые могут войти в эти 5 милисекунд.

Разумным правилом является не встраивать в функции, которые имеют больше чем 3 строки кода в них. Исключением из этого правила являются случаи где известен параметр как константа compiletime и, как результат этой постоянной компилятор сможет оптимизировать большинство вашей функции во время компиляции. Для хорошего примера этого более позднего случая, см. встроенную функцию kmalloc().

Часто люди утверждают, что добавление встроенного к статическим и используемым функциям только один раз всегда выигрывает, так как там не является компромиссом в пространстве. Хотя это технически корректный, gcc способен вставляя их автоматически без помощи и обслуживания удаление встроенного, когда второй пользователь оказывается перевешивает потенциальную ценность подсказки, которая подсказывает gcc сделать что-то в любом случае.

Ответ 3

Я согласен с другими сообщениями:

  • inline может быть излишним, потому что компилятор сделает это
  • Inline может раздувать ваш код.

В-третьих, это может заставить вас раскрывать детали реализации в ваших заголовках, например,

class OtherObject;

class Object {
public:
    void someFunc(OtherObject& otherObj) {
        otherObj.doIt(); // Yikes requires OtherObj declaration!
    }
};

Без встроенного объявления вам понадобилось только одно объявление ForwardOffject. С помощью встроенного header требуется определение для OtherObject.

Ответ 4

Как уже упоминалось, ключевое слово inline является лишь подсказкой для компилятора. На самом деле большинство современных компиляторов полностью игнорируют этот намек. У компилятора есть своя эвристика, чтобы решить, следует ли встроить функцию и, откровенно говоря, не хотите, чтобы вы советовали, большое вам спасибо.

Если вы действительно хотите сделать что-то встроенное, если вы действительно профилировали его и посмотрели на разборку, чтобы убедиться, что переопределение эвристики компилятора действительно имеет смысл, тогда это возможно:

  • В VС++ используйте ключевое слово __forceinline
  • В GCC используйте __attribute __ ((always_inline))

Ключевое слово inline имеет вторую, действительную цель - объявление функций в файлах заголовков, но не внутри определения класса. Ключевое слово inline необходимо, чтобы сообщить компилятору не генерировать несколько определений функции.

Ответ 5

Возникает проблема с inline - как только вы определили функцию в заголовочном файле (что подразумевает встроенную, явную или неявную, определяя тело функции-члена внутри класса), нет простого способа ее изменить, не форсируя пользователям перекомпилировать (в отличие от релинка). Часто это вызывает проблемы, особенно если рассматриваемая функция определена в библиотеке, а заголовок является частью ее интерфейса.

Ответ 6

Я сомневаюсь. Даже компилятор автоматически устанавливает некоторые функции для оптимизации.

Ответ 7

Я не знаю, был ли мой ответ связан с вопросом, но:

Будьте очень осторожны с встроенными виртуальными методами! Некоторые багги-компиляторы (например, предыдущие версии Visual С++) генерируют встроенный код для виртуальных методов, где стандартное поведение должно было ничего не делать, кроме как спуститься по дереву наследования и вызвать соответствующий метод.

Ответ 8

Следует также отметить, что ключевое слово inline является только запросом. Компилятор может выбрать не встраивать его, так как компилятор может выбрать встроенную функцию, которую вы не определяли как встроенную, если она считает, что компромисс скорости/размера стоит того.

Это решение принято на основе нескольких вещей, таких как настройка между оптимизацией для скорости (исключает вызов функции) и оптимизацию для размера (вставка может вызвать раздувание кода, поэтому это не удобно для больших многократно используемых функций).

с компилятором VС++ вы можете переопределить это решение, используя __forceinline

SO в целом: Используйте inline, если вы действительно хотите иметь функцию в заголовке, но в других местах это мало, потому что, если вы собираетесь что-либо извлечь из этого, хороший компилятор сделает его встроенным для вас в любом случае.

Ответ 9

Вложение больших функций может сделать программу более крупной, что приведет к большему количеству промахов в кеше и замедлению работы.

Решение о том, что функция достаточно мала, чтобы наложение увеличило производительность, довольно сложно. Руководство по стилю Google С++ рекомендует только встраивать функции из 10 строк или меньше.

Ответ 10

Чрезмерная инкрустация функций может увеличить размер скомпилированного исполняемого файла, который может отрицательно повлиять на производительность кэша, но в настоящее время компилятор принимает решение о встраивании функции самостоятельно (в зависимости от многих критериев) и игнорирует ключевое слово inline.

Ответ 11

Среди других проблем с встроенными функциями, которые я видел сильно злоупотребляемыми (я видел встроенные функции из 500 строк), вы должны знать:

  • построить нестабильность

    • Изменение источника встроенной функции заставляет всех пользователей заголовка перекомпилировать
    • #include утечка в клиент. Это может быть очень неприятно, если вы переработаете встроенную функцию и удалите ненужный заголовок, на который полагался какой-то клиент.
  • исполняемый размер

    • Каждый раз, когда встроенная строка встроена вместо команды вызова, компилятор должен сгенерировать весь код встроенного. Это нормально, если код функции короткий (одна или две строки), не очень хорошо, если функция длинная
    • Некоторые функции могут генерировать намного больше кода, чем сначала. В данном случае я считаю "тривиальным" деструктором класса, который имеет много переменных-членов (или две или три элемента с довольно беспорядочными деструкторами). Вызов должен быть сгенерирован для каждого деструктора.
  • время выполнения

    • это очень зависит от вашего кэша процессора и общих библиотек, но важна локальность ссылок. Если код, который вы, возможно, встраиваете, происходит в кэше процессора в одном месте, несколько клиентов могут найти код, который не страдает от промаха в кеше и последующей выборки памяти (и, что еще хуже, если это произойдет, выборка диска), К сожалению, это один из тех случаев, когда вам действительно нужно провести анализ производительности.

Стандарт кодирования, в котором я работаю, ограничивает встроенные функции простыми сеттерами/геттерами и, в частности, говорит, что деструкторы не должны быть встроенными, если у вас нет измерений производительности, чтобы показать, что вставка дает заметное преимущество.

Ответ 12

  • Как говорили другие люди, встроенная функция может создать проблему, если код большой. Поскольку каждая команда хранится в определенной ячейке памяти, поэтому перегрузка встроенной функции делает код более продолжительным, чтобы получить exicuted.

  • Есть несколько других ситуаций, когда встроенная строка не работает

    • не работает в случае рекурсивной функции.
    • Он также может не работать со статической переменной.
    • он также не работает в случае использования цикла, switch и т.д., мы можем сказать, что с несколькими операторами.
    • И функция main не может работать как встроенная функция.