Вставка кода C++
есть ли разница в следующий код:
class Foo
{
inline int SomeFunc() { return 42; }
int AnotherFunc() { return 42; }
};
будут ли обе функции вставлены? Действительно ли inline имеет значение? Есть ли какие-либо правила о том, когда вы должны или не должны встроенный код? Я часто использую AnotherFunc
синтаксис (например, аксессоры), но я редко указываю inline
напрямую.
9 ответов
обе формы должны быть вставлены одинаково. Inline является неявным для тел функций, определенных в определении класса.
на inline
ключевое слово по существу является подсказкой компилятору. Используя inline
не гарантирует, что ваша функция будет быть встроенным, и не упуская его гарантирует, что это не. Вы просто даете компилятору знать, что было бы неплохо постараться встроить эту конкретную функцию.
class Foo
{
inline int SomeFunc() { return 42; }
int AnotherFunc() { return 42; }
};
правильно, что оба способа гарантированно компилируются одинаково. Однако предпочтительнее не делать ни того, ни другого. Согласно C++ FAQ вы должны объявить его обычно внутри определения класса, а затем определить его вне определения класса, внутри заголовка, с явным inline ключевое слово. Как описано в FAQ, это связано с тем, что вы хотите отделить объявление и определение для удобочитаемости других (объявление эквивалент "что" и определение "как").
действительно ли inline имеет значение?
да, если компилятор предоставляет встроенный запрос, он сильно отличается. Подумайте о встроенном коде как о макросе. Везде, где он вызывается, вызов функции заменяется фактическим кодом в определении функции. Это может привести к раздуванию кода при встроенных больших функциях, но компилятор обычно защищает вас от этого, не предоставляя встроенный запрос, если функция слишком велика.
есть ли какие-либо правила о том, когда вы должны или не должны встроенный код?
Я не знаю никаких жестких+быстрых правил, но ориентиром является только встроенный код, если он вызывается часто, и он относительно мал. Сеттеры и геттеры обычно встроены. Если он находится в особенно высокопроизводительной области кода, следует рассмотреть встроенную вставку. Всегда помните, что вы торгуете скоростью выполнения для исполняемого размера с помощью инлайнинг.
VC++ поддерживает __forceinline и __declspec (noinline) директивы, если вы думаете, что знаете лучше, чем компилятор. Подсказка: вы, вероятно, нет!
Inline является подсказкой компилятора и не заставляет компилятор встроить код (по крайней мере, в C++). Таким образом, короткий ответ-это компилятор и, вероятно, контекстно-зависимый, что произойдет в вашем примере. Большинство хороших компиляторов, вероятно, встроили бы оба, особенно из-за очевидной оптимизации постоянного возврата от обеих функций.
В общем inline не то, о чем вы должны беспокоиться. Это приносит преимущество производительности в том, что не нужно выполнять машинные инструкции для создания кадра стека и возвращение управления потоком. Но во всех случаях, кроме самых специализированных, я бы сказал, что это тривиально.
Inline важен в двух случаях. Если вы находитесь в режиме реального времени и не отвечает достаточно быстро. Во-вторых, если профилирование кода показало значительное узкое место в действительно узком цикле (т. е. подпрограмму, вызываемую снова и снова), тогда может помочь вставка.
конкретные приложения и архитектуры также могут привести вас к встраиванию в качестве оптимизация.
Я нашел некоторые компиляторы C++ (т. е. SunStudio) жалуются, если inline опущен, как в
int AnotherFunc() { return 42; }
поэтому я бы рекомендовал всегда использовать ключевое слово inline в этом случае. И не забудьте удалить ключевое слово inline если вы позже реализуете метод как фактический вызов функции, это действительно испортит связывание (в SunStudio 11 и 12 и Borland C++ Builder). Я бы предложил минимальное использование встроенного кода, потому что при прохождении кода с отладчиком он будет "шаг в" встроенный код даже при использовании команды "шаг через", это может быть довольно раздражающим.
обратите внимание, что вне класса, inline
делает что-то более полезное в коде: заставляя (ну, вроде) компилятор C++ генерировать встроенный код при каждом вызове функции, он предотвращает несколько определений одного и того же символа (подпись функции) в разных единицах перевода.
поэтому, если вы вставляете функцию, не являющуюся членом, в файл заголовка и включаете это в несколько файлов cpp, у вас нет компоновщика, кричащего на вас. Если функция слишком велика для вас, чтобы предложите inline-ing, сделайте это способом C: объявите в заголовке, определите в cpp.
Это имеет мало общего с тем, действительно ли код встроен: он позволяет стиль реализации в заголовке, как это обычно для коротких функций-членов.
(Я предполагаю, что компилятор будет умным, если ему нужен не встроенный рендеринг функции, как для функций шаблона, но...)
также добавить к тому, что сказал Грег, при предварительной оптимизации (т. е. inline
-ing) компилятор консультируется не только с ключевыми словами в коде, но и с другими аргументами командной строки, указывающими, как компилятор должен оптимизировать код.