статические переменные во встроенной функции

Многие объяснения уже присутствуют, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать рекомендациям, чтобы избежать NullPointerException вообще.

См. также: A хороший список лучших практик

Я бы добавил, очень важно, хорошо использовать модификатор final. Использование "окончательной" модификатор, когда это применимо в Java

Сводка:

  1. Используйте модификатор final для обеспечения хорошей инициализации.
  2. Избегайте возврата null в методы, например, при возврате пустых коллекций.
  3. Использовать аннотации @NotNull и @Nullable
  4. Быстрое завершение работы и использование утверждений, чтобы избежать распространения нулевых объектов через все приложение, когда они не должен быть пустым.
  5. Сначала используйте значения с известным объектом: if("knownObject".equals(unknownObject)
  6. Предпочитают valueOf() поверх toString ().
  7. Используйте null safe StringUtils StringUtils.isEmpty(null).

74
задан jonrsharpe 19 February 2015 в 21:53
поделиться

9 ответов

Я предполагаю, что Вы пропускаете что-то, здесь.

статическая функция?

Объявление функциональных помех сделает "скрытым" в его единице компиляции.

имя А, имеющее объем пространства имен (3.3.6), имеет внутреннюю связь, если это - название [1 116]

— переменная, функциональный или шаблон функции, который явно объявляется статичный;

3.5/3 - C++ 14 (n3797)

, Когда имя имеет внутреннюю связь, объект, который это обозначает, может быть упомянут именами от других объемов в той же единице перевода.

3.5/2 - C++ 14 (n3797)

, Если Вы объявляете эту статическую функцию в заголовке, тогда все единицы компиляции включая этот заголовок будут иметь свою собственную копию функции.

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

подставляемая функция?

Объявление, которое это встраивает, делает его кандидатом на встраивание (это не означает много в наше время в C++, поскольку компилятор встроит или нет, иногда игнорируя факт, встроенное ключевое слово присутствует или отсутствует):

объявление функции А (8.3.5, 9.3, 11.3) со встроенным спецификатором объявляет подставляемую функцию. Встроенный спецификатор указывает к реализации, что встроенная замена тела функции при вызове должна быть предпочтена обычному механизму вызова функции. Реализация не требуется, чтобы выполнять эту встроенную замену при вызове; однако, даже если эта встроенная замена будет опущена, другие правила для подставляемых функций, определенных 7.1.2, нужно все еще уважать.

7.1.2/2 - C++ 14 (n3797)

В заголовке, имеет интересный побочный эффект: встроенная функция может быть определена многократно в том же модуле, и компоновщик просто присоединится к "ним" в одного (если они не были встроены по причине компилятора).

Для статических переменных, объявленных внутри, в стандарте конкретно говорится там один и только один из них:

А статическая локальная переменная в подставляемой функции экстерна всегда относится к тому же объекту.

7.1.2/4 - C++ 98/C++ 14 (n3797)

(функции экстерном по умолчанию, таким образом, если Вы конкретно не отмечаете свою функцию как статичную, это относится к той функции)

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

статическая локальная переменная?

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

статичный + встроенный?

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

Ответ на дополнительный вопрос автора

, Так как я записал вопрос, я испытал его с 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 static void doSomething()
{
   static int value ;
}

имеет тот же результат, чем не добавление этого "встроенного" ключевого слова, насколько статическая переменная внутри затронута.

, Таким образом, поведение VC ++ корректно, и Вы путаете реальное значение "встроенных" и "статических".

95
ответ дан paercebal 24 November 2019 в 11:57
поделиться

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

Думают как компилятор на мгновение - как это могло быть иначе? Каждая единица компиляции (исходный файл) независима от других и может быть скомпилирована отдельно; каждый должен поэтому создать копию переменной, думая, что это - единственное. У компоновщика есть способность достигнуть через те границы и скорректировать ссылки и для переменных и для функций.

37
ответ дан Mark Ransom 24 November 2019 в 11:57
поделиться

Это, как предполагается, этот путь. "статичный" говорит компилятору, что Вы хотите, чтобы функция была локальна для единицы компиляции, поэтому Вы хотите одну копию на единицу компиляции и одну копию статических переменных на экземпляр функции.

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

Примечание: этот ответ был записан в ответ на ответ исходный плакат, отправленный на себя.

5
ответ дан Raphaël Saint-Pierre 24 November 2019 в 11:57
поделиться

Так как я записал вопрос, я испытал его с Visual Studio 2008. Я пытался включить все опции, которые заставляют VS действовать в соответствии со стандартами, но возможно, что я скучал по некоторым. Это результаты:

, Когда функция просто "встроена", существует только одна копия статической переменной.

, Когда функция "статична встроенный", существует столько же копий, сколько существуют единицы перевода.

реальный вопрос состоит теперь в том, как ли вещами, предполагается, является этот путь, или если это - индивидуальная особенность Microsoft C ++ компилятор.

3
ответ дан Dirk Groeneveld 24 November 2019 в 11:57
поделиться

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

-1
ответ дан Windows programmer 24 November 2019 в 11:57
поделиться

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

-1
ответ дан Robert Gould 24 November 2019 в 11:57
поделиться

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

-2
ответ дан Jason Etheridge 24 November 2019 в 11:57
поделиться

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

-2
ответ дан 24 November 2019 в 11:57
поделиться

Я нашел ответ Марка Рэнсома полезным - компилятор создает много копий статической переменной, но компоновщик выбирает одну и применяет ее ко всем единицам перевода.

В другом месте я нашел это:

См. [Dcl.fct.spec] / 4

[..] Встроенная функция с внешней связью должна иметь то же адрес во всех единицах перевода. Статическая локальная переменная во внешнем встроенная функция всегда обращается к одному и тому же объекту. Строковый литерал в Встроенная функция extern - это один и тот же объект в разных единицах перевода.

У меня нет копии стандарта для проверки, но он соответствует моему опыту проверки сборки в VS Express 2008

13
ответ дан 24 November 2019 в 11:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: