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
}

Я думаю, что цитата должна быть более ясной о том, что не может быть вписано:

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

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

Другие вопросы по тегам