Перемещение встроенных методов из файла заголовка в файлы .cpp

У меня есть следующий класс, определенный вfoo.h заголовочный файл

class Foo {

public:
    inline int Method();

};

inline int Foo::Method() { // Implementation }

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

#include `foo.h`

inline int Foo::Method() { // Implementation }

У меня есть два вопроса:

Мое заявление об удаленииinline ключевое слово правильно? Должен ли он быть обязательно удален?Как обычно удалениеinline Ключевое слово влияет на производительность (практически все мои методы встроены)?

Заранее большое спасибо.

 user118218311 июн. 2013 г., 23:46
inline просто указывает, что вы хотите, чтобы функция была встроенной, окончательное решение принимает компилятор, он решает, будет ли ваша функция встроенной или нет.
 Peter Wood11 июн. 2013 г., 23:49
Это'вполне возможно, что он будет встроен в некоторых местах, а не в других, или вообще отсутствует, или везде, или изменит его во время выполнения и т. д.

Ответы на вопрос(6)

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

В файле реализации это также довольно избыточно.

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

Оптимизация для современных компиляторов туманаЕще более избыточные, они в любом случае без всяких вопросов встраивают что-либо в поле зрения или игнорируют ваше ключевое слово по желанию.

Встроенное использование должно быть последовательным! От 7.1.2p4:

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

 JackOLantern12 июн. 2013 г., 09:21
+1. Большое спасибо за ответ.

inline по старинке.

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

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

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

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

Итак, зная это, почему люди все еще используют?inline

Там'только одна причина использоватьinline в наше время, и этоs, чтобы обойти одно правило определения (ODR).

В C / C ++ выРазрешается определять функцию только один раз. Если вы делаете это:

int foo() { /* do something */ }
int foo() { /* do something else */ }

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

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

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

Другими словами,inline теперь значитЯ хочу определить эту функцию в заголовке. "

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

Ради интереса, естьПара мест, где функции неявно делаются встроенными. Одна из них находится в функциях члена класса:

struct Foo {
    void bar() { /* do something */ }
};

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

Другое место в шаблонах. С шаблонамииметь быть определены в заголовках, ониосвободить от УСО иinlineИх использование является излишним.

 JackOLantern12 июн. 2013 г., 09:27
+1 и спасибо за разъяснения.
Решение Вопроса

вы ДОЛЖНЫ удалитьinline ключевое слово allвсе места для этой функции. С более старыми линкерами это может сделать вещи немного медленнее, но с современными линкерами выдолжен не заметить реальной разницы в производительности. *

В некоторых случаях публичная функция-член может бытьinline, но это'Это просто плохая идея. Дон»не делай этого. Аргументы могут быть сделаны для маркировки определенных функций частного члена какinline, но на самом деле то, что вы действительно хотите, чтобы те были__attribute__((always_inline)) или же__forceinline

* В очень редких случаях это будет иметь значение, но в 99% случаев он выиграл »т, и 99,9% чегооставил тебя нене волнует. Если измерения показывают, что вы попали в одну из десяти тысяч, вы можете использовать вышеупомянутое.__forceinline

 JackOLantern12 июн. 2013 г., 09:22
@MooingDuck Большое спасибо за ваш ответ. Я позабочусь о ваших советах. +1 и принимаю.
 Pete12 июн. 2013 г., 00:41
Вы, конечно, несделать это для общественных функций членов. я имею__forceinlined частная функция-член, хотя в результате профилирования.
 Pete12 июн. 2013 г., 00:26
Однако, если функция, помеченная как inline, вызывается только из одной и той же единицы перевода, вы все равно можете указать inline в cpp. Обычно это не так для публичной функции-члена. Если оно's только для использования классом, он, вероятно, будет закрытым. В любом случае компилятор (или некоторые компоновщики) может встроить такие функции в любом случае, если он решит, что это целесообразно.
 Mooing Duck12 июн. 2013 г., 00:47
@Пит:__forceinline а такжеinline разные звери, но яупомяну это
 David Hammen12 июн. 2013 г., 00:09
+1 за единственный правильный ответ на этот вопрос.
 Mooing Duck12 июн. 2013 г., 00:34
@ Пит: этоэто правда, но я хотел бы рассмотреть встраивание в cppдействительно плохая идея, даже если она работает в определенных случаях.

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

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

Если вы переместите функцию вfoo.cpp», он будет ТОЛЬКО встроенным внутриfoo.cpp» модуль компиляции (как правило, модуль компиляции = исходный файл).

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

Редактировать:

Согласно мышейкомментарий: Анinline функция несделать реальное имя функции в объектном файле, поэтому компоновщик может также выдавать ошибки дляunresolved symbol int Foo::Method() [или какую-то формулировку в той степени].

Конец редактирования.

Если производительность критична, вы должны измерить текущий кодЗатем внесите изменения и измерьте их снова. Если оно'значительно отличается, выЯ получу ваш ответ. Если оно's быстрее (например, из-за меньшего количества вложений, приводящих к большей частоте обращений к кешу для других битов кода), тогдахорошо. Если оно'медленнее, тыВам придется вернуть (некоторые из) функций в заголовочный файл. Или жить с этим медленнее ... Или найти какой-то другой способ сделать это снова быстрее ... Выбор за вами (и, если вы работаете в группе, некоторые другие люди могут иметь право голоса в окончательном решении, конечно ). Это'Почти невозможно сказать для SURE, каким путем это будет происходить, по крайней мере, без понимания всей архитектуры программ и что происходит в классе - который, учитывая название "foo.cpp» в посте наверное не РЕАЛЬНЫЙ код ...

 Mooing Duck12 июн. 2013 г., 00:12
нет упоминания о возможных ошибках компоновщика для перемещенияinline определение функции в файл cpp?
 JackOLantern12 июн. 2013 г., 09:25
@ Матс Петерссон +1 за четкое объяснение. Благодарю.

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

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

 Mooing Duck11 июн. 2013 г., 23:57
Это неТ ответ на вопрос вообще.

2. How typically the removal of the inline keyword affect the performance (practically all my methods are inlined)?

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

inline Ключевое слово должно использоваться только с небольшими функциями. Функции Get и Set являются хорошими примерами. Они устанавливают значение одной переменной или возвращают значение одной переменной.

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

 Doug12 июн. 2013 г., 00:13
Возвращаясь и снова читая вопрос и ваш ответ, я осознал свою ошибку. Я думал, что его два вопроса были взаимоисключающими. Вы были правы и спасибо, что помогли мне понять вопрос / ответ. Я бы +1 тебе, если бы мог.
 Mooing Duck12 июн. 2013 г., 00:05
Если [inline] ключевое слово будет удалено? "
 Doug12 июн. 2013 г., 00:03
Не уверен, как это не такt (попытка) ответить на его второй вопрос. Я только что сказал, что добавление / удаление встроенного ключевого слова увеличивает / уменьшает производительность его программы в зависимости от реализации встроенной функции. Так как он неЧтобы показать реализацию своих функций, я сделал свой ответ общим. Потом опять яЯ новичок здесь, и я прошу прощения, если мой ответ невнести значительный вклад ".
 Mooing Duck11 июн. 2013 г., 23:57
Это нене пытаюсь ответить на вопрос вообще.

Ваш ответ на вопрос