Полагаю, вы здесь что-то упускаете.
статическая функция?
Объявление функции статической сделает ее «скрытой» в ее модуле компиляции.
Имя, имеющее область пространства имен (3.3.6), имеет внутреннюю связь, если это имя
- переменная, функция или шаблон функции, который явно объявлен статическим;
3.5 / 3 - C ++ 14 (n3797)
Когда имя имеет внутреннюю связь, на объект, который оно обозначает, можно ссылаться по именам из других областей в той же единице перевода.
3.5 / 2 - C ++ 14 (n3797)
Если вы объявите эту статическую функцию в заголовке, тогда все единицы компиляции, включая этот заголовок, будут иметь свою собственную копию функции.
Дело в том, что если внутри этой функции есть статические переменные, каждая единица компиляции, включающая этот заголовок, также будет иметь свою собственную персональную версию.
встроенная функция?
Объявление его встроенным делает его кандидатом для встраивания (в настоящее время это не имеет большого значения для C ++, поскольку компилятор будет встроенным или нет, иногда игнорируя факт наличия или отсутствия ключевого слова inline):
Объявление функции (8.3.5, 9.3, 11.3) со встроенным спецификатором объявляет встроенную функцию. Встроенный спецификатор указывает реализации, что встроенная подстановка тела функции в точке вызова предпочтительнее обычного механизма вызова функции. Реализация не требуется для выполнения этой встроенной замены в точке вызова; однако, даже если эта встроенная подстановка опущена, все равно должны соблюдаться другие правила для встроенных функций, определенные в 7.1.2.
7.1.2 / 2 - C ++ 14 (n3797)
В заголовке это имеет интересный побочный эффект: встроенная функция может быть определена несколько раз в одном и том же модуле, и компоновщик просто объединит «их» в один (если они не были встроены по причине компилятора).
Для статических переменных, объявленных внутри, в стандарте конкретно говорится, что есть одна и только одна из них:
Статическая локальная переменная во встроенной функции extern всегда ссылается на один и тот же объект.
7.1.2 / 4 - C ++ 98 / C ++ 14 (n3797)
(функции по умолчанию являются extern, поэтому, если вы специально не отметили свою функцию как статическую, это относится к этой функции)
У этого есть преимущество "статики" (т.е. он может быть определен в заголовке) без недостатков (он существует не более одного раза, если он не встроен)
статическая локальная переменная?
Статические локальные переменные не имеют связи (на них нельзя ссылаться по имени вне их области видимости), но имеют статическую продолжительность хранения (т. Е. Глобальные, но их создание и уничтожение подчиняются определенным правилам).
статический + встроенный?
Смешивание встроенных и статических будет иметь описанные вами последствия (даже если функция встроена, статическая переменная внутри не будет, и вы закончите с таким количеством статических переменных, сколько у вас есть единиц компиляции, включая определение ваших статических функций ).
Ответ на дополнительный вопрос автора
Поскольку я написал вопрос, я попробовал его с Visual Studio 2008. Я попытался включить все параметры, которые заставляют VS работать в соответствии со стандартами, но возможно, что я пропустил некоторые. Вот результаты:
Когда функция просто «встроенная», есть только одна копия статической переменной.
Когда функция является «статической встроенной», существует столько копий, сколько единиц перевода.
Настоящий вопрос теперь в том, должно ли быть так, или это идиосинкразия компилятора Microsoft C ++.
Полагаю, у вас есть что-то вроде этого:
void doSomething()
{
static int value ;
}
Вы должны понимать, что статическая переменная внутри функции, проще говоря, глобальная переменная, скрытая для всех, кроме области действия функции, а это означает, что только функция, которая объявлена внутри, может достичь ее.
Встраивание функции ничего не изменит:
inline void doSomething()
{
static int value ;
}
Будет только одна скрытая глобальная переменная. Тот факт, что компилятор попытается встроить код, не изменит того факта, что существует только одна глобальная скрытая переменная.
Теперь, если ваша функция объявлена статической:
static void doSomething()
{
static int value ;
}
Затем он является «частным» для каждой единицы компиляции, что означает, что каждый файл CPP, включая заголовок, в котором объявлена статическая функция, будет иметь свою собственную частную копию функции, включая свою собственную частную копию глобальной скрытой переменной, то есть столько переменных, сколько есть единицы компиляции, включая заголовок.
Добавление «inline» к «статической» функции со «статической» переменной внутри:
inline static void doSomething()
{
static int value ;
}
имеет тот же результат, что и отсутствие этого "встроенного" ключевого слова, что касается статической переменной внутри.
Итак, поведение VC ++ правильное, и вы ошибаетесь в истинном значении слов «встроенный» и «статический».
inline void doSomething() { static int value ; }
, функция имеет внешнюю связь; это нарушение ODR, если оно появляется в заголовке, включенном в два разных блокаinline
это не может нарушать ODR.Я считаю, что компилятор создает много копий переменной, но компоновщик выбирает одну и заставляет все остальные ссылаться на нее. У меня были аналогичные результаты, когда я пытался создать разные версии встроенной функции; если функция фактически не была встроена (режим отладки), все вызовы переходили к одной и той же функции независимо от исходного файла, из которого они были вызваны.
Подумайте на мгновение как компилятор - как могло быть иначе? Каждая единица компиляции (исходный файл) не зависит от других и может быть скомпилирована отдельно; поэтому каждый должен создать копию переменной, считая ее единственной. Компоновщик может выходить за эти границы и настраивать ссылки как для переменных, так и для функций.
источник
Я нашел ответ Марка Рэнсома полезным - компилятор создает много копий статической переменной, но компоновщик выбирает одну и применяет ее ко всем единицам перевода.
В другом месте я нашел это:
См. [Dcl.fct.spec] / 4
У меня нет копии стандарта для проверки, но он соответствует моему опыту изучения сборки в VS Express 2008
источник
Так и должно быть. «static» сообщает компилятору, что вы хотите, чтобы функция была локальной по отношению к модулю компиляции, поэтому вам нужна одна копия на модуль компиляции и одна копия статических переменных на экземпляр функции.
"inline" используется, чтобы сообщить компилятору, что вы хотите, чтобы функция была встроена; в настоящее время он просто воспринимает это как «нормально, если есть несколько копий кода, просто убедитесь, что это одна и та же функция». Так что все используют статические переменные.
Примечание: этот ответ был написан в ответ на ответ, который автор отправил самому себе.
источник
inline
заставляет функцию быть встроенной, или можно иметь несколько копий?inline
не вызывают встраивания, он просто предлагает это и допускает более одного определения (но не в одном модуле компиляции).Поскольку я написал вопрос, я попробовал его с Visual Studio 2008. Я попытался включить все параметры, которые заставляют VS работать в соответствии со стандартами, но возможно, что я пропустил некоторые. Вот результаты:
Когда функция просто «встроенная», есть только одна копия статической переменной.
Когда функция является «статической встроенной», существует столько копий, сколько единиц перевода.
Настоящий вопрос сейчас в том, должно ли быть так, или это идеосинкразия компилятора Microsoft C ++.
источник
Встраивание означает, что исполняемый код (инструкции) встраивается в код вызывающей функции. Компилятор может сделать это независимо от того, просили ли вы об этом. Это не влияет на переменные (данные), объявленные в функции.
источник
Я считаю, что у вас будет по одному на каждую единицу перевода. Фактически у вас есть много версий этой функции (и объявленной статической переменной), по одной для каждой единицы перевода, включающей заголовок.
источник
Помимо каких-либо проблем с дизайном, это все может означать, поскольку вы уже застряли в этом, вы должны использовать static в этом случае, а не inline. Таким образом, у всех одни и те же переменные. (Статическая функция)
источник
Статический означает, что одна копия распространяется по всей программе, но встроенная означает, что для нее требуется один и тот же код несколько раз в одной программе, поэтому невозможно сделать переменную статической внутри встроенной функции.
источник