C++ - Когда встраивание функций невозможно?
Folks,
Я читал " Мышление в C++" (функции Chap - Inline), где я столкнулся с этим утверждением.
"Компилятор также не может выполнить встраивание, если адрес функции взят неявно или явно".
Что это значит "taking address of function implicitly or explicitly
"?
Почему нельзя встроить в этом случае?
Благодарю.
3 ответа
На самом деле, цитата может ввести в заблуждение.
Если адрес функции взят, то необходимо сгенерировать функцию в библиотеке / исполняемом файле, потому что выполнение функции по ее адресу состоит в переходе указателя инструкции к блоку кода, описывающего функцию.
Тем не менее, это, безусловно, не мешает компилятору встроить функцию в других местах при непосредственном вызове.
Сначала обзор:
// Explicit:
void foo();
void (*func_ptr)() = foo;
// Implicit
struct Foo { virtual void bar() {} }; // address used in V-Table
Во-вторых, в качестве примеров:
int main() {
(*func_ptr)(); // probably not inlined as the compiler can difficultly assert
// that nobody may modified it... since it's non-const.
foo(); // might be inlined
Foo f;
f.bar(); // might be inlined (the exact type of `f` is known)
// this is called, "devirtualizing"
Foo& g = accessSomeFoo();
g.bar(); // probably not inlined unless the compiler can assert
// the type returned by accessSomeFoo
// (which requires knowing its definition)
}
Взятие адреса функции означает присвоение его указателю функции. Это может произойти явно, как в связанных примерах. Я не уверен, что автор подразумевает под "неявным образом" - возможно, такими вещами, как передача функции в качестве параметра другой функции.
Если адрес функции взят, он должен иметь адрес в первую очередь. Поскольку встраивание означает в основном замену вызовов функции копией ее тела, после такого преобразования функция больше не существует и, следовательно, не имеет адреса - только n различных копий идентичного кода в местах, где раньше были вызовы этой функции. Таким образом, если адрес функции используется каким-либо образом, он не может быть встроенным.
Я не уверен, правда ли это. Однако, если вы берете адрес функции, эта функция должна существовать в памяти вместе с преамбулой функции и кодом очистки. Это преамбула и очистка, которые пропускаются при вставке. И вы получаете целую кучу возможностей оптимизации, когда встроены.
Но современный компилятор все еще должен иметь возможность встроить функцию везде, где это возможно. Рассматривать:
int compare (int a, int b)
{
return a compared to b
}
int main ()
{
a = array of ints
qsort (a, compare); // take address of compare function, thus compare function exists in
// app as a proper function
compare (value1, value2); // there's no reason why this can't be inlined
}
Я думаю, что цитата должна быть более ясной о том, что не может быть вписано:
Функция, которая вызывается через указатель на функцию, не может быть встроенной.
Это связано с тем, что во время компиляции невозможно определить, какую функцию встроить в точке косвенного вызова (вызов через указатель функции). Это не означает, что функция, на которую указывает указатель функции, не может быть встроена, где бы она ни вызывалась напрямую.