Никогда не следует использовать статическую встроенную функцию?

Есть два последствия использования inline ключевое слово (§ 7.1.3/4):

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

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

Дальнейшее #2Как я понимаю, когда вы объявляете функцию как static inline функция,

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

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

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

5 ответов

Решение

Ваш анализ верен, но не обязательно подразумевает бесполезность. Даже если большинство компиляторов выполняют автоматически встроенные функции (причина № 1), лучше объявить inline просто чтобы описать намерение.

Не обращая внимания на взаимодействие с inline, static функции следует использовать с осторожностью. static модификатор в области именного пространства ранее считался устаревшим в пользу безымянных пространств имен (C++03 §D.2). По какой-то неясной причине, что я не могу вспомнить, он был удален из устаревшего в C++11, но вам это редко нужно.

Таким образом, на практике маркировка статических и встроенных функций бесполезна. Либо он должен быть статическим (не наиболее предпочтительным) или встроенным (наиболее предпочтительным),

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

Что предпочтительнее, так это использовать безымянное пространство имен вместо static:

namespace {
    inline void better(); // give the function a unique name
}

static inline void worse(); // kludge the linker to allowing duplicates

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

С помощью static inline имеет смысл, когда встроенная функция не используется за пределами модуля перевода. Используя его, вы можете предотвратить случайное нарушение правила ODR, назвав другую встроенную функцию в другом модуле перевода с тем же именем.

Пример:

source1.cpp:

inline int Foo()
{
  return 1;
}

int Bar1()
{
  return Foo();
}

source2.cpp:

inline int Foo()
{
  return 2;
}

int Bar2()
{
  return Foo();
}

Без использования static on Foo (или без использования анонимного пространства имен, которое предпочитается большинством программистов на C++), этот пример нарушает ODR и результаты не определены. Вы можете протестировать в Visual Studio результат Bar1/Bar2 будет зависеть от настроек компилятора - в конфигурации отладки и Bar1, и Bar2 будут возвращать одно и то же значение (встраивание не используется, одна реализация выбрана произвольно компоновщиком), в конфигурации Release каждый из них вернет предполагаемое значение.

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

То есть только с static inline вы действительно можете заменить использование макроса, inline само по себе не достаточно.

Простой поиск в Google по запросу "static inline" покажет вам страницы документации компилятора, в которых говорится об этом. Думаю, этого должно быть достаточно, чтобы ответить на ваш вопрос и сказать: "Нет, это практически бесполезно". Вот один пример сайта, обсуждающего использование inlineи конкретно static inline http://www.greenend.org.uk/rjk/tech/inline.html

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

Однако, когда мы говорим о методах членов (class сфера), static inline Функция имеет значение.
Как только вы объявите class метод как inline, его полное тело должно быть видимым для всех единиц перевода, включая class,

Помни что static Ключевое слово имеет другое значение, когда речь идет о class,
Изменить: Как вы можете знать, что static функция внутри class не имеет внутренней связи, другими словами класс не может иметь разные копии своих static метод в зависимости от перевода (.cpp) единиц.
Но свободный static функционировать в namespace /global scope имеет разные копии для каждой единицы перевода.

например

// file.h
static void foo () {}
struct A {
  static void foo () {}
};

// file1.cpp
#include"file.h"
void x1 ()
{
  foo();  // different function exclusive to file1.cpp
  A::foo();  // same function
}

// file2.cpp
#include"file.h"
void x2 ()
{
  foo();  // different function exclusive to file2.cpp
  A::foo();  // same function
}

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

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