Вопрос

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

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

Решение

Да, функции, которые определены внутри тела класса, неявно inline.

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

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

Как указано другими, метод, определяемый в классе, автоматически запрашивается встроенным. Полезно понять, почему.

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

class A {
public:
  void f() { ... your code ... }
};

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

A__f_v:

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

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

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

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

Рассмотрим этот встроенный код:

inline int add(int a, int b) { return a + b; }

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

И, если вы проходите в константах:

int c= add(5,4);

Это разрешено во время компиляции, и кода нет.

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

На другом конце спектра, предположим, что вы запросите встроенный в линии на 1000 линейной части кода. Даже если ваш компилятор достаточно глуп, чтобы согласиться с ним, единственное, что вы сохраняете, - это сам вызов, и стоимость состоит в том, что каждый раз, когда вы его называете, компилятор должен вставить весь этот код. Если вы называете этот код n Times , ваш код растет на размер рутины * n. Таким образом, что -то большее, чем 10 линий, в значительной степени не стоит внедрять, за исключением особого случая, когда его называют очень маленьким количеством раз. Примером этого может быть личный метод, который называется только 2 другими.

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

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

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

Это действительно вставлено - но любой встроенный запрос может быть проигнорирован компилятором.

Это запрос компилятору, который он может игнорировать.

Стандарт ISO C++ 2003 года гласит:

7.1.2/2 Объявление функции (8.3.5, 9.3, 11.4) с встроенным спецификатором объявляет встроенную функцию.Встроенный спецификатор указывает на реализацию, что встроенное замену корпуса функции в точке вызова должно быть предпочтительным для обычного вызова функции
механизм.Реализация не требуется для выполнения этого встроенного
замена на месте вызова;однако, даже если это встроенное
Замена опущена, другие правила для встроенных функций, определенных 7.1.2, все еще должны соблюдаться.

7.1.2/3 Функция, определенная в определении класса, является встроенной
функция.Встроенный спецификатор не должен отображаться в объявлении функции блока.

7.1.2/4 Встроенная функция должна быть определена в каждой единице перевода в
который он используется и должен иметь точно одинаковое определение в каждом
случай (3.2).[Примечание:Вызов к встроенной функции может быть встречен
Перед его дефицитом появится в блоке перевода.] Если функция с внешней связью объявлена ​​в линейке в одной единице перевода, она должна быть объявлена ​​в строке во всех единицах перевода, в которых она появляется;никакой диагностики не требуется.Встроенная функция с внешней связью должна иметь одинаковый адрес во всех единицах перевода.Статическая локальная переменная на внешней встроенной
Функция всегда относится к одному и тому же объекту.Строковый литерал в
Внешняя встроенная функция - это один и тот же объект в разных переводах
единицы измерения.

Есть две вещи, которые не следует смешивать:

  1. Как пометить функцию как встроенную:определите его с помощью строки перед подписью или определите его в точке объявления;
  2. Как компилятор будет относиться к такой встроенной маркировке:независимо от того, как вы пометили функцию как встроенную, компилятор будет рассматривать ее как запрос.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top