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

StackOverflow https://stackoverflow.com/questions/60830

  •  09-06-2019
  •  | 
  •  

Вопрос

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

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

Заключение:

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

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

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

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

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

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

Это было полезно?

Решение

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

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

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

Другие советы

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

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

Редактировать: вот что такое линукс Стиль кодирования в документе об этом сказано:

Глава 15:Встроенная болезнь

Похоже, что существует распространенное неправильное восприятие, что у GCC есть магия «заставляйте меня быстрее», называемой «inline».Хотя использование встроенных может быть подходящим (например, в качестве средства замены макросов, см. Главу 12), оно не часто.Обильное использование встроенного ключевого слова приводит к гораздо большему ядру, что, в свою очередь, замедляет систему в целом, из -за большего следов ICACHE для процессора и просто потому, что для PageCache меньше памяти.Просто подумай об этом;Мисс, пропускающая ядра вызывает поиск диска, который легко занимает 5 милисекунд.Есть много циклов процессора, которые могут попасть в эти 5 милисекунд.

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

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

Согласен с другими постами:

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

Третий момент: это может заставить вас раскрыть детали реализации в заголовках, например:

class OtherObject;

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

Без встроенного объявления все, что вам нужно, — это предварительное объявление OtherObject.С встроенным вашему заголовку нужна определение для другого объекта.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • создать нестабильность

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

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

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

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

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

  2. есть несколько других ситуаций, когда встроенный режим может не работать

    1. не работает в случае рекурсивной функции.
    2. Он также может не работать со статической переменной.
    3. это также не работает в случае использования цикла, переключателя и т. д. или мы можем сказать это с несколькими операторами.
    4. И функция main не может работать как встроенная функция.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top