Никогда не следует использовать статическую встроенную функцию?
Есть два последствия использования inline
ключевое слово (§ 7.1.3/4):
- Он намекает компилятору, что замена тела функции в точке вызова предпочтительнее обычного механизма вызова функции.
- Даже если внутренняя замена не указана, соблюдаются другие правила (особенно в отношении одного правила определения) для встроенной замены.
Обычно любой основной компилятор заменяет тело функции в точке вызова, если это необходимо, поэтому маркировка функции 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 с флагом компилятора. В случае флага, он встроен в функцию, и если он также является статическим и указывается в каждом вызываемом экземпляре, то он избавляется от определения функции, которое никогда не будет использоваться в созданном объектном файле, тем самым уменьшая размер сгенерированного кода на этот бит.