Почему встроенные функции C++ в заголовке?
NB это не вопрос о том, как использовать встроенные функции и как они работают, почему они сделали так, как они.
объявление функции-члена класса не нужно определять функцию как inline, это только фактическая реализация функции. Например, в заголовочном файле:
struct foo{
void bar(); // no need to define this as inline
}
так почему же встроенная реализация класса function есть чтобы быть в заголовочном файле? Почему я не могу поставить встроенную функцию ? Если я где попробовать поставить определение в .cpp файл я бы получил ошибку по строкам:
error LNK2019: unresolved external symbol
"public: void __thiscall foo::bar(void)"
(?bar@foo@@QAEXXZ) referenced in function _main
1>C:UsersMeDocumentsVisual Studio 2012ProjectsinlineDebuginline.exe
: fatal error LNK1120: 1 unresolved externals
8 ответов:
определение
inlineфункция не должна быть в заголовочном файле, но из-за одно правило определения для встроенных функций, идентичное определение функции должно существовать в каждой единице перевода, которая использует его.самый простой способ добиться этого-поместить определение в файл заголовка.
если вы хотите поместить определение функции в единой исходный файл, то вы не должны объявить его
inline. А функции нет объявленоinlineне означает, что компилятор не может встроить функцию.следует ли объявлять функцию
inlineили нет, как правило, выбор, который вы должны сделать на основе какой версии правила одного определения это имеет смысл для вас, чтобы следовать; добавлениеinlineи тогда ограничение последующими ограничениями имеет мало смысла.
есть два способа смотреть на это:
встроенные функции объявляются в заголовке, потому что для того, чтобы встроить вызов функции, компилятор должен иметь возможность видеть тело функции. Для наивного компилятора для этого тело функции должно находиться в той же единице перевода, что и вызов. (Современный компилятор может оптимизировать все единицы перевода, и поэтому вызов функции может быть встроен, даже если определение функции находится в отдельной единице перевода, но эти оптимизация стоит дорого, не всегда включена и не всегда поддерживается компилятором)
функции, объявленные в заголовке должны быть помечены
inlineпотому что в противном случае каждая единица перевода, включающая заголовок, будет содержать определение функции, и компоновщик будет жаловаться на несколько определений (нарушение правила одного определения). Элементinlineключевое слово подавляет это, позволяя содержать несколько единиц перевода (идентичные) определение.два объяснения действительно сводятся к тому, что
inlineключевое слово не делать то, что вы ожидаете.компилятор C++ может свободно применять встраивание оптимизация (замените вызов функции телом вызываемой функции, экономя накладные расходы на вызов) в любое удобное для него время, если это не изменяет наблюдаемое поведение программы.
The
inlineключевое слово делает его легче чтобы компилятор применил эту оптимизацию, разрешив определение функции быть видимым в нескольких единицах перевода, но использование ключевого слова не означает компилятор и чтобы встроить функцию, и не использование ключевого слова не запрещает компилятору вставлять функцию.
Это предел компилятора C++. Если вы помещаете функцию в заголовок, все файлы cpp, в которые она может быть встроена, могут видеть "источник" вашей функции, и вставка может быть выполнена компилятором. В противном случае встраивание должно было бы выполняться компоновщиком (каждый файл cpp компилируется в obj-файл отдельно). Проблема в том, что это было бы гораздо сложнее сделать в компоновщике. Аналогичная проблема существует с" шаблонными " классами / функциями. Они должны быть созданы с помощью компилятор, потому что компоновщик будет иметь проблемы с созданием экземпляров (создание специализированной версии) их. Некоторые новые компиляторы / компоновщики могут выполнять компиляцию/компоновку" два прохода", где компилятор выполняет первый проход, затем компоновщик выполняет свою работу и вызывает компилятор для разрешения неразрешенных вещей (inline/templates...)
причина в том, что компилятор должен видеть определение для того, чтобы иметь возможность бросить его в место вызова.
помните, что C и C++ используют очень упрощенную модель компиляции, где компилятор всегда видит только одну единицу перевода за раз. (Это не удается для экспорта, что является основной причиной того, что только один поставщик фактически реализовал его.)
c++
inlineключевое слово вводит в заблуждение, это не означает "встроенная функция". Если функция определена как встроенная, это просто означает, что она может быть определена несколько раз, пока все определения равны. Это совершенно законно для функции с пометкойinlineчтобы быть реальной функцией, которая вызывается вместо того, чтобы получать код, встроенный в точке, где он вызывается.определение функции в заголовочном файле необходимо для шаблонов, так как, например, шаблонный класс на самом деле не является класс, это шаблон для класса, который вы можете сделать несколько вариаций. Для того, чтобы компилятор мог, например, сделать
Foo<int>::bar()функции при использовании шаблона Foo для создания класса Foo, определениемFoo<T>::bar()должен быть виден.
Я знаю, что это старая нить, но подумал, что я должен упомянуть, что
externключевое слово. Я недавно столкнулся с этой проблемой и решил следующим образомпомощником.h
namespace DX { extern inline void ThrowIfFailed(HRESULT hr); }помощником.cpp
namespace DX { inline void ThrowIfFailed(HRESULT hr) { if (FAILED(hr)) { std::stringstream ss; ss << "#" << hr; throw std::exception(ss.str().c_str()); } } }
потому что компилятор должен видеть их, чтобы inline них. А файлы заголовков - это "компоненты", которые обычно включаются в другие единицы перевода.
#include "file.h" // Ok, now me (the compiler) can see the definition of that inline function. // So I'm able to replace calls for the actual implementation.
Встроенные Функции
В C++ Micro-это не что иное, как встроенная функция. Так что теперь микроны находятся под контролем компилятора.
- важно : если мы определим функцию внутри класса, он станет Inline автоматически
код встроенной функции заменяется в месте его вызова, поэтому он уменьшает накладные расходы на вызов функции.
в некоторых случаях встраивание функции не могут работать, Например,
Если статическая переменная используется внутри inline функцию.
Если функция сложная.
Если рекурсивный вызов функции
если адрес функции берется неявно или явно
функция, определенная вне класса, как показано ниже, может стать встроенной
inline int AddTwoVar(int x,int y); //This may not become inline inline int AddTwoVar(int x,int y) { return x + y; } // This becomes inlineфункция, определенная внутри класса, также становится встроенной
// Inline SpeedMeter functions class SpeedMeter { int speed; public: int getSpeed() const { return speed; } void setSpeed(int varSpeed) { speed = varSpeed; } }; int main() { SpeedMeter objSM; objSM.setSpeed(80); int speedValue = A.getSpeed(); }здесь и getSpeed и setSpeed функции станут встроенными
Comments