Встраивать эту функцию или нет? - PullRequest
4 голосов
/ 23 декабря 2010

Я должен реализовать функцию, которая сравнивает две строки одинаково, поэтому strcmp, но игнорируя пробельные символы, поэтому

strcmpignorews("abc   ", " a b c")

должен дать тот же результат.

Вот моя реализация:

namespace {
    void SkipWhitespace(const char *&s) {
        for (; std::isspace(*s, std::locale::classic); ++s);
    }
}

int strcmpignorews(const char *s1, const char *s2) {
    for (; *s1 != '\0' && *s2 != '\0'; ++s1, ++s2) {
        SkipWhitespace(s1);
        SkipWhitespace(s2);

        if (*s1 != *s2) {
            break;
        }
    }

    return (*s1 < *s2) ? -1 : ((*s1 == *s2) ? 0 : 1);
}

Теперь вопрос в том, имеет ли смысл встроить функцию SkipWhitespace? Мне кажется, я где-то читал, что inline не следует использовать для функций, содержащих циклы или переключатели, но я не могу вспомнить, где и почему.

Ответы [ 5 ]

14 голосов
/ 23 декабря 2010

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

Чтобы подчеркнуть, будет ли компилятор выполнять встроенную оптимизацию, полностью не в ваших руках .

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

3 голосов
/ 23 декабря 2010

В общем Профиль до встраивания .

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

Если вы не возражаете против дополнительной типизации, вот несколько рекомендаций по объявлению метода или функции как встроенных:

  1. Содержимое метода использует меньше или равно инструкциициклы для вызова, инициализации, очистки и возврата из метода.
  2. Метод не имеет переходов или переходов к другим методам.
  3. Метод не имеет циклов (в настоящее время небольшие циклы могут соответствоватьв кэш процессора).
  4. В методе используются только методы, которые являются встроенными или могут быть встроенными, включая библиотечные функции.
  5. Вы конвертируете макрос (#define).
  6. Метод проходит вышеуказанные тесты (кроме 5) и тщательно протестирован.(Можете ли вы сказать, перестроить все зависимости, потому что вы изменили заголовок?)

Мой стиль - встроенные методы получения и установки класса.Любой код, который является изменчивым (либо не работает, либо подвержен изменениям), либо является сложным, не будет встроен.

3 голосов
/ 23 декабря 2010

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

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

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

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

Профилировщик может сказать вам, что определенная функция может повысить производительность, если она встроена, но не может сказать, может ли конкретная встроенная функция повысить производительность (размер, время выполнения, развитие, ...), если она не встроена.

3 голосов
/ 23 декабря 2010

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

Просто имейте в виду, что inline - это предложение для компилятораон может свободно игнорировать, если обнаружит, что вы не правы или даже просто отвратителен.Я редко использую его и редко нахожу в этом необходимость, относя его к той же категории, что и auto и register (по крайней мере, в C).

2 голосов
/ 23 декабря 2010

В этом контексте нет никакого вреда и, возможно, какой-то пользы в использовании inline.

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

Стилистически, я бы использовал while цикл вместо вашего for цикла:

while (isspace(*s, std::locale::classic))
    ++s;

Это также исправляет ошибку в вашем коде, которая пропускает только те символы, которые не являются пробелами. ( Ошибка была исправлена ​​во время ввода этого ответа! )

...